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_IsWirelessConnect
  28. find_get_fstype
  29. find_Restart
  30. find_add_ptp_handler
  31. find_PT_PlaySound
  32. find_getImageDirName
  33. match_GetImageFolder
  34. find_GetImageFolder
  35. match_GetDrive_ClusterSize
  36. find_GetDrive_ClusterSize
  37. find_GetDrive_TotalClusters
  38. find_srand
  39. find_malloc_strictly
  40. find_DisplayBusyOnScreen
  41. find_UndisplayBusyOnScreen
  42. find_CreateDialogBox
  43. find_DisplayDialogBox
  44. find_add_ui_to_dialog
  45. find_get_string_by_id
  46. find_get_self_task_errno_pointer
  47. find_get_nd_value
  48. find_get_current_nd_value_iris
  49. find_get_current_nd_value
  50. find_get_current_deltasv
  51. find_getcurrentmachinetime
  52. find_sethptimeraftertimeout
  53. find_DoMovieFrameCapture
  54. find_get_ptp_buf_size
  55. find_GetBaseSv
  56. find_Remove
  57. find_dispatch_funcs
  58. find_func
  59. dryos_offset
  60. fw_string_process
  61. fw_string_process_unaligned
  62. fw_process
  63. match_strsig1
  64. match_strsig2a
  65. match_strsig2
  66. match_strsig3a
  67. match_strsig3
  68. match_strsig4a
  69. match_strsig4
  70. match_strsig5a
  71. match_strsig5
  72. match_strsig6
  73. match_strsig7a
  74. match_strsig7
  75. match_strsig8
  76. find_strsig8
  77. find_strsig9
  78. match_strsig11
  79. find_strsig12
  80. match_strsig13a
  81. match_strsig13
  82. match_strsig15a
  83. match_strsig15
  84. match_strsig16
  85. find_strsig17
  86. find_strsig19
  87. match_strsig23a
  88. match_strsig23
  89. match_strsig24
  90. find_strsig
  91. find_str_sig_matches
  92. find_matches
  93. print_results
  94. mode_name
  95. output_modemap
  96. match_modelist
  97. match_FlashParamsTable2
  98. match_FlashParamsTable
  99. find_modemap
  100. match_CAM_UNCACHED_BIT
  101. find_DebugAssert_argcount
  102. find_platform_vals
  103. find_viewport_address
  104. match_vid_get_bitmap_fb
  105. match_get_flash_params_count
  106. match_uiprop_count
  107. match_imager_active
  108. find_lib_vals
  109. print_stubs_min
  110. print_exmem_types
  111. find_exmem_alloc_table
  112. match_levent_table
  113. match_movie_status
  114. match_full_screen_refresh
  115. match_canon_shoot_menu_active
  116. match_playrec_mode
  117. match_some_flag_for_af_scan
  118. match_palette_data
  119. match_palette_buffer_offset
  120. match_palette_data3
  121. match_palette_data2
  122. match_SavePaletteData
  123. match_viewport_address3
  124. match_viewport_address2
  125. match_viewport_address
  126. match_physw_status
  127. match_physw_run
  128. match_canon_menu_active
  129. match_zoom_busy
  130. match_focus_busy
  131. match_bitmap_buffer2
  132. match_bitmap_buffer
  133. match_raw_buffer
  134. match_fileiosem
  135. match_cameracon_state
  136. find_stubs_min
  137. find_ctypes
  138. match_nrflag3
  139. match_nrflag
  140. match_nrflag2
  141. isSTRw
  142. isSTRB
  143. find_leds
  144. find_task_related_info
  145. find_AdditionAgent_RAM
  146. add_prop_hit
  147. match_propsig1a
  148. match_propsig1
  149. find_strsig2
  150. find_prop_matches
  151. find_propset
  152. find_other_vals
  153. print_kval
  154. print_physw_raw_vals
  155. add_kinfo
  156. add_kmval
  157. kinfo_compare
  158. print_kmvals
  159. match_GetSDProtect
  160. find_key_vals
  161. get_eventproc_val
  162. add_func_name
  163. add_func_name2
  164. match_eventproc
  165. match_registerproc2
  166. match_registerproc
  167. match_registerlists
  168. find_eventprocs
  169. findTaskAddress
  170. match_createtask
  171. find_tasks
  172. find_builddate
  173. save_ptp_handler_func
  174. find_ptp_handler_imm
  175. match_ptp_handlers
  176. find_ptp_handlers
  177. write_levent_table_dump
  178. output_firmware_vals
  179. compare_func_names
  180. compare_func_addresses
  181. write_funcs
  182. 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", },
 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     { "get_current_deltasv", },
 349     { "GetUsableAvRange", OPTIONAL|UNUSED },
 350     { "GetBaseSv", OPTIONAL|UNUSED },
 351     { "GetCurrentDriveBaseSvValue", },
 352 
 353     { "kbd_p1_f" },
 354     { "kbd_p1_f_cont" },
 355     { "kbd_p2_f" },
 356     { "kbd_read_keys" },
 357     { "kbd_read_keys_r2" },
 358 
 359     { "kbd_pwr_off", OPTIONAL },
 360     { "kbd_pwr_on", OPTIONAL },
 361     { "lseek" },
 362     { "malloc" },
 363     { "memcmp" },
 364     { "memcpy" },
 365     { "memset" },
 366     { "mkdir" },
 367     { "mktime_ext" },
 368     { "open" },
 369     { "OpenFastDir" },
 370     { "closedir" },
 371     { "get_fstype", OPTIONAL|LIST_ALWAYS },
 372     { "qsort" },
 373     { "rand" },
 374     { "read", UNUSED|OPTIONAL },
 375     { "realloc", OPTIONAL|LIST_ALWAYS },
 376     { "reboot_fw_update" },
 377     { "set_control_event" },
 378     { "srand" },
 379     { "stat" },
 380     { "strcat" },
 381     { "strchr" },
 382     { "strcmp" },
 383     { "strcpy" },
 384     { "strftime" },
 385     { "strlen" },
 386     { "strncmp" },
 387     { "strncpy" },
 388     { "strrchr" },
 389     { "strtol" },
 390     { "strtolx" },
 391 
 392     { "task_CaptSeq" },
 393     { "task_DvlpSeqTask", OPTIONAL },
 394     { "task_ExpDrv" },
 395     { "task_FileWrite", OPTIONAL },
 396     { "task_InitFileModules" },
 397     { "task_MovieRecord" },
 398     { "task_PhySw", OPTIONAL },
 399     { "task_RotaryEncoder", OPTIONAL },
 400     { "task_TouchPanel", OPTIONAL },
 401 
 402     { "hook_CreateTask" },
 403 
 404     { "time" },
 405     { "vsprintf" },
 406     { "write", UNUSED|OPTIONAL },
 407 
 408     { "EngDrvIn", OPTIONAL|UNUSED|LIST_ALWAYS },
 409     { "EngDrvOut", OPTIONAL|UNUSED|LIST_ALWAYS },
 410     { "EngDrvRead" },
 411     { "EngDrvBits", OPTIONAL|UNUSED|LIST_ALWAYS },
 412 
 413     { "PTM_GetCurrentItem" },
 414     { "PTM_SetCurrentItem", UNUSED|LIST_ALWAYS },
 415     { "PTM_NextItem", OPTIONAL|UNUSED|LIST_ALWAYS },
 416     { "PTM_PrevItem", OPTIONAL|UNUSED|LIST_ALWAYS },
 417     { "PTM_SetPropertyEnable", OPTIONAL|UNUSED|LIST_ALWAYS },
 418 
 419     { "DisableISDriveError", OPTIONAL },
 420 
 421     // OS functions, mostly to aid firmware analysis. Order is important!
 422     { "_GetSystemTime", OPTIONAL|UNUSED|LIST_ALWAYS }, // only for locating timer functions
 423     { "SetTimerAfter", OPTIONAL|UNUSED|LIST_ALWAYS },
 424     { "SetTimerWhen", OPTIONAL|UNUSED|LIST_ALWAYS },
 425     { "CancelTimer", OPTIONAL|UNUSED|LIST_ALWAYS },
 426     { "CancelHPTimer" },
 427     { "SetHPTimerAfterTimeout", OPTIONAL|UNUSED|LIST_ALWAYS },
 428     { "SetHPTimerAfterNow" },
 429     { "CreateTaskStrictly", OPTIONAL|UNUSED|LIST_ALWAYS },
 430     { "CreateTaskStrictly_alt", OPTIONAL|UNUSED|LIST_ALWAYS }, // widely used in r59, identical to CreateTaskStrictly
 431     { "CreateMessageQueue", OPTIONAL|UNUSED|LIST_ALWAYS },
 432     { "CreateRecursiveLock", OPTIONAL|UNUSED|LIST_ALWAYS },
 433     { "GetSemaphoreValue", OPTIONAL|UNUSED|LIST_ALWAYS },
 434     { "TryTakeSemaphore", OPTIONAL|UNUSED|LIST_ALWAYS },
 435     { "CreateMessageQueueStrictly", OPTIONAL|UNUSED|LIST_ALWAYS },
 436     { "CreateEventFlagStrictly", OPTIONAL|UNUSED|LIST_ALWAYS },
 437     { "CreateBinarySemaphoreStrictly", OPTIONAL|UNUSED|LIST_ALWAYS },
 438     { "CreateCountingSemaphoreStrictly", OPTIONAL|UNUSED|LIST_ALWAYS },
 439     { "CreateRecursiveLockStrictly", OPTIONAL|UNUSED|LIST_ALWAYS },
 440     { "TakeSemaphoreStrictly", OPTIONAL|UNUSED|LIST_ALWAYS }, // r23+
 441     { "ReceiveMessageQueueStrictly", OPTIONAL|UNUSED|LIST_ALWAYS }, // r23+
 442     { "PostMessageQueueStrictly", OPTIONAL|UNUSED|LIST_ALWAYS },    // r23+
 443     { "WaitForAnyEventFlagStrictly", OPTIONAL|UNUSED|LIST_ALWAYS }, // r23+
 444     { "WaitForAllEventFlagStrictly", OPTIONAL|UNUSED|LIST_ALWAYS }, // r23+
 445     { "AcquireRecursiveLockStrictly", OPTIONAL|UNUSED|LIST_ALWAYS }, // r23+
 446     { "DeleteMessageQueue", OPTIONAL|UNUSED|LIST_ALWAYS },
 447     { "PostMessageQueue", OPTIONAL|UNUSED|LIST_ALWAYS },
 448     { "ReceiveMessageQueue", OPTIONAL|UNUSED|LIST_ALWAYS },
 449     { "TryReceiveMessageQueue", OPTIONAL|UNUSED|LIST_ALWAYS },
 450     { "TryPostMessageQueue", OPTIONAL|UNUSED|LIST_ALWAYS },
 451     { "GetNumberOfPostedMessages", OPTIONAL|UNUSED|LIST_ALWAYS },
 452     { "DeleteRecursiveLock", OPTIONAL|UNUSED|LIST_ALWAYS },
 453     { "AcquireRecursiveLock", OPTIONAL|UNUSED|LIST_ALWAYS },
 454     { "ReleaseRecursiveLock", OPTIONAL|UNUSED|LIST_ALWAYS },
 455     { "WaitForAnyEventFlag", OPTIONAL|UNUSED|LIST_ALWAYS },
 456     { "WaitForAllEventFlag", OPTIONAL|UNUSED|LIST_ALWAYS },
 457     { "ClearEventFlag", OPTIONAL|UNUSED|LIST_ALWAYS },
 458     { "SetEventFlag", OPTIONAL|UNUSED|LIST_ALWAYS },
 459     { "GetEventFlagValue", OPTIONAL|UNUSED|LIST_ALWAYS },
 460     { "CreateEventFlag", OPTIONAL|UNUSED|LIST_ALWAYS },
 461     { "DeleteEventFlag", OPTIONAL|UNUSED|LIST_ALWAYS },
 462     { "CheckAnyEventFlag", OPTIONAL|UNUSED|LIST_ALWAYS },
 463     { "CheckAllEventFlag", OPTIONAL|UNUSED|LIST_ALWAYS },
 464     { "RegisterInterruptHandler", OPTIONAL|UNUSED|LIST_ALWAYS },
 465     { "UnregisterInterruptHandler", OPTIONAL|UNUSED|LIST_ALWAYS },
 466     { "GetSRAndDisableInterrupt", OPTIONAL|UNUSED|LIST_ALWAYS }, // disables IRQ, returns a value
 467     { "SetSR", OPTIONAL|UNUSED|LIST_ALWAYS }, // enables IRQ, puts back value returned by GetSR
 468     { "EnableInterrupt", OPTIONAL|UNUSED|LIST_ALWAYS }, // enables IRQ
 469     { "_divmod_signed_int", OPTIONAL|UNUSED|LIST_ALWAYS}, // division for signed integers, remainder is returned in r1
 470     { "_divmod_unsigned_int", OPTIONAL|UNUSED|LIST_ALWAYS}, // division for unsigned integers, remainder is returned in r1
 471     { "_dflt", OPTIONAL|UNUSED|LIST_ALWAYS}, // int -> double
 472     { "_dfltu", OPTIONAL|UNUSED|LIST_ALWAYS}, // uint -> double
 473     { "_dfix", OPTIONAL|UNUSED|LIST_ALWAYS}, // double -> int
 474     { "_dfixu", OPTIONAL|UNUSED|LIST_ALWAYS}, // double -> uint
 475     { "_dmul", OPTIONAL|UNUSED|LIST_ALWAYS}, // double precision float multiplication
 476     { "_ddiv", OPTIONAL|UNUSED|LIST_ALWAYS}, // double precision float division
 477     { "_dadd", OPTIONAL|UNUSED|LIST_ALWAYS}, // addition for doubles
 478     { "_dsub", OPTIONAL|UNUSED|LIST_ALWAYS}, // subtraction for doubles
 479     { "_drsb", OPTIONAL|UNUSED|LIST_ALWAYS}, // reverse subtraction for doubles (?)
 480     { "_dcmp", OPTIONAL|UNUSED|LIST_ALWAYS}, // comparison of 2 doubles, only updates condition flags
 481     { "_dcmp_reverse", OPTIONAL|UNUSED|LIST_ALWAYS}, // like _dcmp, but operands in reverse order, only updates condition flags
 482     { "_safe_sqrt", OPTIONAL|UNUSED|LIST_ALWAYS}, // only calls _sqrt for numbers >= 0
 483     { "_scalbn", OPTIONAL|UNUSED|LIST_ALWAYS}, // double scalbn (double x, long exp), returns x * FLT_RADIX ** exp
 484     { "_fflt", OPTIONAL|UNUSED|LIST_ALWAYS}, // int -> float
 485     { "_ffltu", OPTIONAL|UNUSED|LIST_ALWAYS}, // uint -> float
 486     { "_ffix", OPTIONAL|UNUSED|LIST_ALWAYS}, // float -> int
 487     { "_ffixu", OPTIONAL|UNUSED|LIST_ALWAYS}, // float -> uint
 488     { "_fmul", OPTIONAL|UNUSED|LIST_ALWAYS}, // single precision float multiplication
 489     { "_fdiv", OPTIONAL|UNUSED|LIST_ALWAYS}, // single precision float division
 490     { "_f2d", OPTIONAL|UNUSED|LIST_ALWAYS}, // float -> double
 491     { "DisplayBusyOnScreen", OPTIONAL|UNUSED|LIST_ALWAYS}, // displays full screen "busy" message
 492     { "UndisplayBusyOnScreen", OPTIONAL|UNUSED|LIST_ALWAYS},
 493     { "CreateDialogBox", OPTIONAL|UNUSED|LIST_ALWAYS},
 494     { "DisplayDialogBox", OPTIONAL|UNUSED|LIST_ALWAYS},
 495     { "add_ui_to_dialog", OPTIONAL|UNUSED|LIST_ALWAYS}, // name made up, assigns resources to a dialog
 496     { "get_string_by_id", OPTIONAL|UNUSED|LIST_ALWAYS}, // name made up, retrieves a localised or unlocalised string by its ID
 497     { "malloc_strictly", OPTIONAL|UNUSED|LIST_ALWAYS }, // name made up
 498     { "GetCurrentMachineTime", OPTIONAL|UNUSED|LIST_ALWAYS }, // reads usec counter, name from ixus30
 499     { "HwOcReadICAPCounter", OPTIONAL|UNUSED|LIST_ALWAYS }, // reads usec counter, name from ixus30
 500     { "get_self_task_id", OPTIONAL|UNUSED|LIST_ALWAYS }, // gets ID of own task
 501     { "get_task_properties", OPTIONAL|UNUSED|LIST_ALWAYS }, // gets copy of task's data (different struct, not the real TCB)
 502     { "get_self_task_errno_pointer", OPTIONAL|UNUSED|LIST_ALWAYS }, // gets pointer to own task's errno
 503     { "EnableDispatch", OPTIONAL|UNUSED }, // enables task switching (high level wrapper)
 504     { "DisableDispatch", OPTIONAL|UNUSED }, // disables task switching (high level wrapper)
 505     { "EnableDispatch_low", OPTIONAL|UNUSED }, // enables task switching
 506     { "DisableDispatch_low", OPTIONAL|UNUSED }, // disables task switching
 507     { "GetValidSystemCalender", OPTIONAL|UNUSED }, // name from ixus30
 508     { "SetValidSystemCalender", OPTIONAL|UNUSED }, // name from ixus30
 509     { "GetTimeFromRTC", OPTIONAL|UNUSED },
 510     { "IsInvalidTime", OPTIONAL|UNUSED }, // name from ixus30
 511     { "PauseTimeOfSystem", OPTIONAL|UNUSED }, // name from ixus30
 512     { "ResumeTimeOfSystem", OPTIONAL|UNUSED }, // name from ixus30
 513 
 514     { "cache_flush_and_enable", OPTIONAL|UNUSED }, // older dryos
 515     { "cache_clean_flush_and_disable", OPTIONAL|UNUSED }, // older dryos
 516     { "cache_flush_range", OPTIONAL|UNUSED }, // older dryos
 517     { "cache_clean_flush_range", OPTIONAL|UNUSED }, // older dryos
 518     { "cache_clean_range", OPTIONAL|UNUSED }, // older dryos
 519 
 520     { "icache_flush_and_enable", OPTIONAL|UNUSED }, // newer dryos
 521     { "icache_disable_and_flush", OPTIONAL|UNUSED }, // newer dryos
 522     { "dcache_flush_and_enable", OPTIONAL|UNUSED }, // newer dryos
 523     { "dcache_clean_flush_and_disable", OPTIONAL|UNUSED }, // newer dryos
 524     { "dcache_flush_range", OPTIONAL|UNUSED }, // newer dryos
 525     { "dcache_clean_range", OPTIONAL|UNUSED }, // newer dryos
 526     { "dcache_clean_flush_range", OPTIONAL|UNUSED }, // newer dryos
 527     { "icache_flush_range", OPTIONAL|UNUSED }, // newer dryos
 528 
 529     // various dryos memory functions, made up names
 530     { "bzero", OPTIONAL|UNUSED },
 531     { "dry_memzero", OPTIONAL|UNUSED },
 532     { "dry_memcpy", OPTIONAL|UNUSED },
 533 
 534     // Other stuff needed for finding misc variables - don't export to stubs_entry.S
 535     { "GetSDProtect", UNUSED },
 536     { "DispCon_ShowBitmapColorBar", UNUSED },
 537     { "ResetZoomLens", OPTIONAL|UNUSED },
 538     { "ResetFocusLens", OPTIONAL|UNUSED },
 539     { "NR_GetDarkSubType", OPTIONAL|UNUSED },
 540     { "NR_SetDarkSubType", OPTIONAL|UNUSED },
 541     { "SavePaletteData", OPTIONAL|UNUSED },
 542     { "GUISrv_StartGUISystem", OPTIONAL|UNUSED|LIST_ALWAYS },
 543     { "get_resource_pointer", OPTIONAL|UNUSED|LIST_ALWAYS }, // name made up, gets a pointer to a certain resource (font, dialog, icon)
 544     { "CalcLog10", OPTIONAL|UNUSED|LIST_ALWAYS }, // helper
 545     { "ImagerActivate", OPTIONAL|UNUSED }, // helper
 546     { "DoMovieFrameCapture", OPTIONAL|UNUSED },
 547     { "SetImageMode", OPTIONAL|UNUSED },
 548     { "MenuIn", OPTIONAL|UNUSED },
 549     { "MenuOut", OPTIONAL|UNUSED },
 550 
 551     { "MFOn", OPTIONAL },
 552     { "MFOff", OPTIONAL },
 553     { "PT_MFOn", OPTIONAL },
 554     { "PT_MFOff", OPTIONAL },
 555     { "SS_MFOn", OPTIONAL },
 556     { "SS_MFOff", OPTIONAL },
 557 
 558     { "GetAdChValue", OPTIONAL },
 559     { "EnableHDMIPower", OPTIONAL },
 560     { "DisableHDMIPower", OPTIONAL },
 561 
 562     { "get_ptp_buf_size", OPTIONAL },
 563     { "get_ptp_file_buf", OPTIONAL },
 564 
 565     { "SetVideoOutType", OPTIONAL },
 566     { "GetVideoOutType", OPTIONAL },
 567 
 568     { "cameracon_set_state", UNUSED }, // made up name, helper for cameracon_state variable
 569     { "cameracon_get_state", OPTIONAL|UNUSED }, // for information only, match doesn't work on early dry
 570 
 571     { "IsWirelessConnect", OPTIONAL },
 572 
 573     { 0, 0, 0 }
 574 };
 575 
 576 // Return the array index of a named function in the array above
 577 int find_saved_sig(const char *name)
 578 {
 579     int i;
 580     for (i=0; func_names[i].name != 0; i++)
 581     {
 582         if (strcmp(name,func_names[i].name) == 0)
 583         {
 584             return i;
 585         }
 586     }
 587     return -1;
 588 }
 589 
 590 // Save the address value found for a function in the above array
 591 void save_sig(const char *name, uint32_t val)
 592 {
 593     int i = find_saved_sig(name);
 594     if (i >= 0)
 595     {
 596         func_names[i].val = val;
 597     }
 598 }
 599 
 600 // Get the saved address value for a named function
 601 // If the address value is 0 then assume the function search has not occurred yet, so go search for it.
 602 int get_saved_sig(firmware *fw, const char *name)
 603 {
 604     int i = find_saved_sig(name);
 605     if (i >= 0)
 606     {
 607         if (func_names[i].val == 0)
 608         {
 609             // See if the function is in the 'func_list' array below
 610             int find_func(const char* name);
 611             int k1 = find_func(name);
 612             if (k1 >= 0)
 613             {
 614                 // if found do full search
 615                 void find_matches(firmware*,const char*);
 616                 find_matches(fw, name);
 617                 count = 0;
 618             }
 619             else
 620             {
 621                 // not found, only do string matching search
 622                 void find_str_sig_matches(firmware*,const char*);
 623                 find_str_sig_matches(fw, name);
 624                 count = 0;
 625             }
 626         }
 627         if (func_names[i].val == 0)
 628         {
 629             // If not found return invalid index
 630             i = -1;
 631         }
 632     }
 633     return i;
 634 }
 635 
 636 // Search for something relative to the location stored for a previously matched function
 637 // Matching is done via the 'func' function, searching continues until 'func' returns non-zero
 638 // Starts searching at 'ofst' from the saved address for a max of 'len' instructions
 639 // Returns the 'func' value or 0 if no match found
 640 int search_saved_sig(firmware *fw, char *sig, int (*func)(firmware*, int, int), int v, int ofst, int len)
 641 {
 642     int k = get_saved_sig(fw, sig);
 643     if (k >= 0)
 644     {
 645         int idx = adr2idx(fw, func_names[k].val);
 646         for (k=idx+ofst; k<idx+ofst+len; k++)
 647         {
 648             int rv = func(fw, k, v);
 649             if (rv)
 650                 return rv;
 651         }
 652     }
 653     return 0;
 654 }
 655 
 656 //------------------------------------------------------------------------------------------------------------
 657 
 658 // Signature min / max DryOS versions
 659 
 660 typedef struct {
 661     char        *name;
 662     uint32_t    val;
 663 } sig_stuff;
 664 
 665 sig_stuff min_ver[] = {
 666     { "ScreenLock", 39 },
 667     { "ScreenUnlock", 39 },
 668     { "MakeSDCardBootable", 47 },
 669     { "hook_CreateTask", 51 },
 670     { "CreateTaskStrictly_alt", 59 },
 671 
 672     { 0, 0 }
 673 };
 674 
 675 sig_stuff max_ver[] = {
 676     { "UpdateMBROnFlash", 45 },
 677     { "kbd_pwr_on", 43 },
 678     { "kbd_pwr_off", 43 },
 679 
 680     { 0, 0 }
 681 };
 682 
 683 int find_min_ver(const char *name)
 684 {
 685     int i;
 686     for (i=0; min_ver[i].name != 0; i++)
 687     {
 688         if (strcmp(name,min_ver[i].name) == 0)
 689         {
 690             return min_ver[i].val;
 691         }
 692     }
 693     return 0;
 694 }
 695 
 696 int find_max_ver(const char *name)
 697 {
 698     int i;
 699     for (i=0; max_ver[i].name != 0; i++)
 700     {
 701         if (strcmp(name,max_ver[i].name) == 0)
 702         {
 703             return max_ver[i].val;
 704         }
 705     }
 706     return 99999;
 707 }
 708 
 709 //------------------------------------------------------------------------------------------------------------
 710 
 711 // New string / signature matching structure
 712 
 713 // Structure for matching
 714 
 715 typedef struct {
 716     int     type;               // 1 = func*, string, 2 = string, ... string*, func*, 3 = ADR Rx, func, ADR Ry, string, BL, ... string, etc
 717     char    *name;              // function name
 718     char    *ev_name;           // event / other name to match in the firmware
 719     int     offset;             // offset for following branches, or other tests
 720     // DryOS version specific offsets
 721     int     dryos20_offset;     // ***** UPDATE for new DryOS version *****
 722     int     dryos23_offset;
 723     int     dryos31_offset;
 724     int     dryos39_offset;
 725     int     dryos43_offset;
 726     int     dryos45_offset;
 727     int     dryos47_offset;
 728     int     dryos49_offset;
 729     int     dryos50_offset;
 730     int     dryos51_offset;
 731     int     dryos52_offset;
 732     int     dryos54_offset;
 733     int     dryos55_offset;
 734     int     dryos57_offset;
 735     int     dryos58_offset;
 736     int     dryos59_offset;
 737 } string_sig;
 738 
 739 // used to early out for wifi related functions, valid after tasks found
 740 int cam_has_wifi;
 741 
 742 // Load old signature matching data generated by gensig_dryos
 743 #include "signatures_dryos.h"
 744 
 745 //------------------------------------------------------------------------------------------------------------
 746 
 747 // Data for matching 'apex2us' function
 748 uint32_t apex2us_test[] = { 0x3D09000, 0x3BBA304, 0x3A728D2, 0x3931EF4, 0x37F8303, 0x36C52A2, 0x3598B85, 0x3472B6A, 0 };
 749 uint32_t apex2us_test2[] = { 0x3d090000, 0x3bba3040, 0x3a728d1f, 0x3931ef45, 0x37f8302c, 0x36c52a26, 0x3598b852, 0x3472b699, 0 }; // r52+?
 750 
 751 // Special case for apex2us
 752 int match_apex2us(firmware *fw, int k, uint32_t v1, __attribute__ ((unused))uint32_t v2)
 753 {
 754     if (isLDR_PC(fw,k) && (LDR2val(fw,k) == v1) && ((fwRd(fw,k) == 1) || (fwRd(fw,k) == 2)))
 755     {
 756         k = find_inst_rev(fw, isSTMFD_LR, k, 200);
 757         if (k != -1)
 758         {
 759             if (fwval(fw,k-2) == 0xE3700D09)    // CMN R0, #0x240
 760                 k -= 2;
 761             uint32_t fadr = idx2adr(fw,k);
 762             fwAddMatch(fw,fadr,32,0,121);
 763             return 1;
 764         }
 765     }
 766     return 0;
 767 }
 768 int match_apex2us2(firmware *fw, int k, uint32_t v1, __attribute__ ((unused))uint32_t v2) // r52+?
 769 {
 770     if (isLDR_PC(fw,k) && (LDR2val(fw,k) == v1) && ((fwRd(fw,k) == 1) || (fwRd(fw,k) == 2)))
 771     {
 772         k = find_inst_rev(fw, isSTMFD_LR, k, 200);
 773         if (k != -1)
 774         {
 775             if (fwval(fw,k+1) != 0xe3700d0f)    // CMN R0, #0x3c0
 776                 return 0;
 777             uint32_t fadr = idx2adr(fw,k);
 778             fwAddMatch(fw,fadr,32,0,121);
 779             return 1;
 780         }
 781     }
 782     return 0;
 783 }
 784 int find_apex2us(firmware *fw, __attribute__ ((unused))string_sig *sig, int j)
 785 {
 786     int i;
 787     int fnd = 1;
 788     for (i=0; apex2us_test[i] != 0; i++)
 789     {
 790         if (fwval(fw,j+i) != apex2us_test[i])
 791         {
 792             fnd = 0;
 793             break;
 794         }
 795     }
 796     if (fnd)
 797     {
 798         return search_fw(fw, match_apex2us, idx2adr(fw,j), 0, 1);
 799     }
 800 
 801     for (i=0; apex2us_test2[i] != 0; i++)
 802     {
 803         if (fwval(fw,j+i) != apex2us_test2[i])
 804         {
 805             return 0;
 806         }
 807     }
 808     return search_fw(fw, match_apex2us2, idx2adr(fw,j), 0, 1);
 809 }
 810 
 811 // Special case for mkdir
 812 int find_mkdir(firmware *fw, __attribute__ ((unused))string_sig *sig, int k)
 813 {
 814     if (fwval(fw,k) == 0x12CEA600)
 815     {
 816         int kk;
 817         if (fw->dryos_ver > 58)
 818         {
 819             kk = k-26;
 820         }
 821         else
 822         {
 823             kk = k-20;
 824         }
 825         k = find_inst_rev(fw, isSTMFD_LR, kk, 200);
 826         if (k != -1)
 827         {
 828             if ((((fwval(fw,k+12) & 0xFFF0FFFF) == 0xE350002F) && ((fwval(fw,k+15) & 0xFFF0FFFF) == 0xE3500021) && ((fwval(fw,k+19) & 0xFFF0FFFF) == 0xE3500020)) ||
 829                 (((fwval(fw,k+11) & 0xFFF0FFFF) == 0xE350002F) && ((fwval(fw,k+14) & 0xFFF0FFFF) == 0xE3500021) && ((fwval(fw,k+18) & 0xFFF0FFFF) == 0xE3500020)))
 830             {
 831                 uint32_t fadr = 0;
 832                 if (isBL(fw,k+47))
 833                 {
 834                     fadr = followBranch(fw, idx2adr(fw,k+47), 0x01000001);
 835                 }
 836                 else if (isBL(fw,k+48))
 837                 {
 838                     fadr = followBranch(fw, idx2adr(fw,k+48), 0x01000001);
 839                 }
 840                 if (fadr != 0)
 841                 {
 842                     fwAddMatch(fw,fadr,32,0,121);
 843                     return 1;
 844                 }
 845             }
 846         }
 847     }
 848     return 0;
 849 }
 850 
 851 // Special case for _pow
 852 int find_pow(firmware *fw, __attribute__ ((unused))string_sig *sig, int j)
 853 {
 854     // Find values passed to _pow
 855     if ((fwval(fw,j) == 0x00000000) && (fwval(fw,j+1) == 0x40000000) && (fwval(fw,j+2) == 0x00000000) && (fwval(fw,j+3) == 0x408F4000))
 856     {
 857         uint32_t adr1 = idx2adr(fw,j);        // address of 1st value
 858         uint32_t adr2 = idx2adr(fw,j+2);    // address of 2nd value
 859         int j1;
 860 
 861         for (j1 = j-5; j1>0; j1--)
 862         {
 863             if (isADR_PC_cond(fw,j1) &&                 // ADR ?
 864                 (fwval(fw,j1+1) == 0xE8900003) &&       // LDMIA R0,{R0,R1}
 865                 isBL(fw,j1+2) &&                        // BL
 866                 isADR_PC_cond(fw,j1+4))                 // ADR ?
 867             {
 868                 if ((ADR2adr(fw,j1) == adr1) && (ADR2adr(fw,j1+4) == adr2))
 869                 {
 870                     uint32_t fadr = followBranch(fw,idx2adr(fw,j1+2),0x01000001);
 871                     fwAddMatch(fw,fadr,32,0,121);
 872                     return 1;
 873                 }
 874             }
 875             else
 876             if (isADR_PC_cond(fw,j1) &&                 // ADR ?
 877                 (fwval(fw,j1+2) == 0xE8900003) &&       // LDMIA R0,{R0,R1}
 878                 isBL(fw,j1+3) &&                        // BL
 879                 isADR_PC_cond(fw,j1+4))                 // ADR ?
 880             {
 881                 if ((ADR2adr(fw,j1) == adr1) && (ADR2adr(fw,j1+4) == adr2))
 882                 {
 883                     uint32_t fadr = followBranch(fw,idx2adr(fw,j1+3),0x01000001);
 884                     fwAddMatch(fw,fadr,32,0,121);
 885                     return 1;
 886                 }
 887             }
 888         }
 889     }
 890 
 891     return 0;
 892 }
 893 
 894 // Special case for rand
 895 int find_rand(firmware *fw, __attribute__ ((unused))string_sig *sig, int j)
 896 {
 897     if (fwval(fw,j) == 0x41C64E6D)
 898     {
 899         int j1;
 900 
 901         for (j1 = j-1; j1>j-30; j1--)
 902         {
 903             if (isLDR_PC_cond(fw,j1) &&         // LDR Rx, =0x41C64E6D
 904                 (LDR2val(fw,j1) == 0x41C64E6D)) // LDMIA R0,{R0,R1}
 905             {
 906                 int k = find_inst_rev(fw, isBX_LR,j1-1,15);
 907                 if (k >= 0)
 908                 {
 909                     uint32_t fadr = idx2adr(fw, k+1);
 910                     fwAddMatch(fw,fadr,32,0,121);
 911                     return 1;
 912                 }
 913             }
 914         }
 915     }
 916 
 917     return 0;
 918 }
 919 // helper used for get_ptp_file_buf and get_ptp_buf_size
 920 int get_ptp_file_buf_id(firmware *fw) {
 921     // ID of the file buffer appears to be 5 for r43-r52
 922     if(fw->dryos_ver >= 43 && fw->dryos_ver <= 52) {
 923         return 5;
 924     } else {
 925         return 4;
 926     }
 927 }
 928 
 929 // Special case for get_ptp_file_buf
 930 int find_get_ptp_file_buf(firmware *fw, __attribute__ ((unused))string_sig *sig, int j)
 931 {
 932     /*
 933      * looking for
 934      * MOV r0,#ptp_file_buf_id
 935      * bl get_ptp_buf_size
 936      * bic r1, r0, #1
 937      * MOV r0,#ptp_file_buf_id
 938      * bl sub...
 939     */
 940     if(!(isMOV_immed(fw,j)
 941         && (fwRn(fw,j) == 0)
 942         && isBL(fw,j+1)
 943         && ((fwval(fw,j+2) & 0xFFF00000) == 0xe3C00000) // BIC
 944         && (ALUop2(fw,j+2) == 1)
 945         && isMOV_immed(fw,j+3)
 946         && (fwRn(fw,j+3) == 0)
 947         && isBL(fw,j+4))) {
 948         return 0;
 949     }
 950     uint32_t file_buf_id = get_ptp_file_buf_id(fw);
 951     if(ALUop2(fw,j) != file_buf_id || ALUop2(fw,j+3) != file_buf_id) {
 952         return 0;
 953     }
 954     uint32_t f1 = followBranch(fw,idx2adr(fw,j+1),0x01000001);
 955     int i = get_saved_sig(fw,"get_ptp_buf_size");
 956     // if sig not found, end search completely
 957     if(i < 0) {
 958         // fprintf(stderr,"find_get_ptp_file_buf func missing @0x%08x\n",idx2adr(fw,j));
 959         return 1;
 960     }
 961     if(f1 != func_names[i].val) {
 962         // fprintf(stderr,"find_get_ptp_file_buf func mismatch @0x%08x\n",idx2adr(fw,j));
 963         return 0;
 964     }
 965 
 966     // search backwards for push
 967     int k = find_inst_rev(fw, isSTMFD_LR, j-1, 8);
 968     if(k < 0) {
 969         // fprintf(stderr,"find_get_ptp_file_buf failed to find push @0x%08x\n",idx2adr(fw,j));
 970         return 0;
 971     }
 972     // functions could have a MOV, LDR etc before the push, but not seen for this function
 973     uint32_t fadr = idx2adr(fw, k);
 974     fwAddMatch(fw,fadr,32,0,121);
 975     // fprintf(stderr,"find_get_ptp_file_buf match @0x%08x\n",fadr);
 976 
 977     return 1;
 978 }
 979 
 980 // Special case for 'closedir'
 981 int find_closedir(firmware *fw)
 982 {
 983     int j = get_saved_sig(fw,"OpenFastDir");
 984     if (j >= 0)
 985     {
 986         int k = find_inst(fw, isSTMFD_LR, adr2idx(fw,func_names[j].val)+1, 100);
 987         if (isB(fw,k-1) && isBL(fw,k-2))
 988         {
 989             uint32_t fadr = followBranch(fw, idx2adr(fw, k-2), 0x01000001);
 990             fwAddMatch(fw,fadr,32,0,121);
 991             return 1;
 992         }
 993     }
 994 
 995     return 0;
 996 }
 997 
 998 int find_GetTimeFromRTC_and_more(firmware *fw, int i)
 999 {
1000     int j = fw->main_offs;
1001     int k = -1;
1002     while (j < fw->size)
1003     {
1004         if (isLDR(fw, j) && LDR2val(fw, j) == 0x7FE8177F)
1005         {
1006             if (i == 2)
1007             {
1008                 k = find_inst(fw, isBL, j+1, 6);
1009                 if (k > j)
1010                 {
1011                     k = adr2idx(fw, followBranch(fw, idx2adr(fw, k), 0x01000001));
1012                     uint32_t fadr = idx2adr(fw, k);
1013                     fwAddMatch(fw,fadr,32,0,122); // SetValidSystemCalender
1014                     return 1;
1015                 }
1016             }
1017             k = find_Nth_inst(fw, isBL, j+1, 6, 2);
1018             break;
1019         }
1020         j++;
1021     }
1022     if (k > j)
1023     {
1024         k = adr2idx(fw, followBranch(fw, idx2adr(fw, k), 0x01000001));
1025         j = find_inst(fw, isBLEQ, k+1, 30);
1026         if (j != -1) // newer cam
1027         {
1028             if (i == 0)
1029             {
1030                 j = adr2idx(fw, followBranch(fw, idx2adr(fw, j), 0xe1000001));
1031                 uint32_t fadr = idx2adr(fw, j);
1032                 fwAddMatch(fw,fadr,32,0,122); // GetTimeFromRTC
1033                 return 1;
1034             }
1035             k = find_Nth_inst_rev(fw, isBL, j-1, 14, 2);
1036             j = adr2idx(fw, followBranch(fw, idx2adr(fw, k), 0x01000001));
1037             if (!isSTMFD_LR(fw,j))
1038             {
1039                 uint32_t fadr = idx2adr(fw, j);
1040                 fwAddMatch(fw,fadr,32,0,122); // GetValidSystemCalender
1041                 return 1;
1042             }
1043             return 0;
1044         }
1045         k = find_Nth_inst(fw, isBL, k+1, 20, 2);
1046         if (k == -1)
1047         {
1048             return 0;
1049         }
1050         j = adr2idx(fw, followBranch2(fw, idx2adr(fw, k), 0x01000001)); // followBranch2 to support s110
1051         if (isSTMFD_LR(fw,j))
1052         {
1053             k = find_inst(fw, isBL, k+1, 8);
1054             if (k == -1)
1055             {
1056                 return 0;
1057             }
1058             j = adr2idx(fw, followBranch(fw, idx2adr(fw, k), 0x01000001));
1059         }
1060         if (isSTMFD_LR(fw,j))
1061         {
1062             return 0;
1063         }
1064         if (i == 1) // GetValidSystemCalender (ixus30/40, sic)
1065         {
1066             uint32_t fadr = idx2adr(fw, j);
1067             fwAddMatch(fw,fadr,32,0,122);
1068             return 1;
1069         }
1070         k = find_inst(fw, isBL, k+1, 8);
1071         if (k == -1)
1072         {
1073             return 0;
1074         }
1075         j = adr2idx(fw, followBranch(fw, idx2adr(fw, k), 0x01000001));
1076         if (i == 0 && isSTMFD_LR(fw,j)) // GetTimeFromRTC
1077         {
1078             uint32_t fadr = idx2adr(fw, j);
1079             fwAddMatch(fw,fadr,32,0,122);
1080             return 1;
1081         }
1082     }
1083 
1084     return 0;
1085 }
1086 
1087 int find_arm_cache_funcs(firmware *fw, int ii)
1088 {
1089     static int cfe=0, ccfd=0, cfr=0, ccfr=0, ccr=0;
1090     static int beenhere = 0;
1091     int i, j=0;
1092     if (!beenhere)
1093     {
1094         beenhere++;
1095         if (ii != 2)
1096         {
1097             j = get_saved_sig(fw,"cache_flush_range");
1098         }
1099         if (j >= 0 && cfr == 0)
1100         {
1101             cfr = adr2idx(fw,func_names[j].val);
1102             i = cfr - 1;
1103             while (i > cfr - 0x100)
1104             {
1105                 if (fwval(fw,i) == 0xe3500000) // cmp r0, #0
1106                 {
1107                     if (ccfd == 0)
1108                     {
1109                         ccfd = i;
1110                     }
1111                     else if (cfe == 0)
1112                     {
1113                         cfe = i;
1114                         break;
1115                     }
1116                 }
1117                 i--;
1118             }
1119             i = cfr + 1;
1120             while (i < cfr + 0x140)
1121             {
1122                 if (fwval(fw,i) == 0xe3500000) // cmp r0, #0
1123                 {
1124                     if (ccfr == 0)
1125                     {
1126                         ccfr = i;
1127                     }
1128                     else if (ccr == 0)
1129                     {
1130                         ccr = i;
1131                         break;
1132                     }
1133                 }
1134                 i++;
1135             }
1136         }
1137         else if (ccr == 0)
1138         {
1139             if (ii != 4)
1140             {
1141                 j = get_saved_sig(fw,"cache_clean_range");
1142             }
1143             if (j >= 0)
1144             {
1145                 ccr = adr2idx(fw,func_names[j].val);
1146                 i = ccr - 1;
1147                 while (i > ccr - 0x300)
1148                 {
1149                     if (fwval(fw,i) == 0xe3500000) // cmp r0, #0
1150                     {
1151                         if (ccfr == 0)
1152                         {
1153                             ccfr = i;
1154                         }
1155                         else if (cfr == 0)
1156                         {
1157                             cfr = i;
1158                         }
1159                         else if (ccfd == 0)
1160                         {
1161                             ccfd = i;
1162                         }
1163                         else if (cfe == 0)
1164                         {
1165                             cfe = i;
1166                             break;
1167                         }
1168                     }
1169                     i--;
1170                 }
1171             }
1172         }
1173     }
1174     if (cfe&&ccfd&&cfr&&ccfr&&ccr)
1175     {
1176         i = 0;
1177         switch (ii)
1178         {
1179             case 0: i = cfe; break;
1180             case 1: i = ccfd; break;
1181             case 2: i = cfr; break;
1182             case 3: i = ccfr; break;
1183             case 4: i = ccr; break;
1184         }
1185         uint32_t fadr = idx2adr(fw, i);
1186         fwAddMatch(fw,fadr,32,0,122);
1187         return 1;
1188     }
1189 
1190     return 0;
1191 }
1192 
1193 int find_arm_cache_funcs2(firmware *fw, int ii)
1194 {
1195     static int ife=0, idf=0, dfe=0, dcfd=0, dfr=0, dcr=0, dcfr=0, ifr=0;
1196     static int beenhere = 0;
1197     int i, j=0;
1198     if (!beenhere)
1199     {
1200         beenhere++;
1201         j = get_saved_sig(fw,"dcache_flush_range");
1202         if (j >= 0 && dfr == 0)
1203         {
1204             dfr = adr2idx(fw,func_names[j].val);
1205             i = dfr - 1;
1206             while (i > dfr - 0x100)
1207             {
1208                 if (fwval(fw,i) == 0xe10f3000) // mrs r3, cpsr
1209                 {
1210                     if (dcfd == 0)
1211                     {
1212                         dcfd = i;
1213                     }
1214                     else if (dfe == 0)
1215                     {
1216                         dfe = i;
1217                     }
1218                     else if (idf == 0)
1219                     {
1220                         idf = i;
1221                     }
1222                     else if (ife == 0)
1223                     {
1224                         ife = i;
1225                         break;
1226                     }
1227                 }
1228                 i--;
1229             }
1230             i = dfr + 1;
1231             while (i < dfr + 0x140)
1232             {
1233                 if (fwval(fw,i) == 0xe3510a02) // cmp r1, #0x2000
1234                 {
1235                     if (dcr == 0)
1236                     {
1237                         dcr = i;
1238                     }
1239                     else if (dcfr == 0)
1240                     {
1241                         dcfr = i;
1242                     }
1243                     else if (ifr == 0)
1244                     {
1245                         ifr = i;
1246                         break;
1247                     }
1248                 }
1249                 i++;
1250             }
1251         }
1252     }
1253     if (ife&&idf&&dfe&&dcfd&&dfr&&dcr&&dcfr&&ifr)
1254     {
1255         i = 0;
1256         switch (ii)
1257         {
1258             case 0: i = ife; break;
1259             case 1: i = idf; break;
1260             case 2: i = dfe; break;
1261             case 3: i = dcfd; break;
1262             case 4: i = dcr; break;
1263             case 5: i = dcfr; break;
1264             case 6: i = ifr; break;
1265         }
1266         uint32_t fadr = idx2adr(fw, i);
1267         fwAddMatch(fw,fadr,32,0,122);
1268         return 1;
1269     }
1270 
1271     return 0;
1272 }
1273 
1274 int find_IsWirelessConnect(firmware *fw, __attribute__ ((unused))int ii)
1275 {
1276     // matches might pick up the wrong function if wifi not present
1277     if(!cam_has_wifi) {
1278         return 0;
1279     }
1280     if (fw->dryos_ver < 53) {
1281         int j = find_str_ref(fw,"WiFiDisconnect");
1282         if(j < 0) {
1283             return 0;
1284         }
1285         int k = find_Nth_inst_rev(fw, isBL, j-1, 5, 1);
1286         if(k < 0) {
1287             return 0;
1288         }
1289         uint32_t fadr = followBranch(fw, idx2adr(fw, k), 0x01000001);
1290         fwAddMatch(fw,fadr,32,0,122);
1291         return 1;
1292     } else {
1293         int j = find_str_ref(fw,"USBDisconnect");
1294         if(j < 0) {
1295             return 0;
1296         }
1297         int k = find_Nth_inst_rev(fw, isBL, j-1, 5, 1);
1298         if(k < 0) {
1299             return 0;
1300         }
1301         uint32_t fadr = followBranch(fw, idx2adr(fw, k), 0x01000001);
1302         fwAddMatch(fw,fadr,32,0,122);
1303         return 1;
1304     }
1305     return 0;
1306 }
1307 
1308 // Special case for 'get_fstype'
1309 int find_get_fstype(firmware *fw)
1310 {
1311     int j = get_saved_sig(fw,"OpenFastDir");
1312     if (j >= 0)
1313     {
1314         int k = find_Nth_inst(fw, isBL, adr2idx(fw,func_names[j].val)+1, 6, 2);
1315         if (k > 0)
1316         {
1317             // sanity check 1
1318             if ( (fwval(fw, k+1) & 0xffff0fff) != 0xe1b00000 ) // movs rx, r0
1319                 return 0;
1320             // sanity check 2
1321             uint32_t cmpinst = ((fwval(fw, k+1) & 0x0000f000)<<4) + 0xe3500004; // cmp rx, #4
1322             int l;
1323             int m = 0;
1324             for (l=0; l<32; l++)
1325             {
1326                 if ( fwval(fw, k+1+l) == cmpinst )
1327                     m++;
1328             }
1329             if (m != 2)
1330                 return 0;
1331             // confirmed
1332             uint32_t fadr = followBranch(fw, idx2adr(fw, k), 0x01000001);
1333             fwAddMatch(fw,fadr,32,0,122);
1334             return 1;
1335         }
1336     }
1337 
1338     return 0;
1339 }
1340 
1341 // Special case for 'Restart'
1342 int find_Restart(firmware *fw)
1343 {
1344     int j = get_saved_sig(fw,"reboot_fw_update");
1345     if (j >= 0)
1346     {
1347         int k = get_saved_sig(fw,"StopWDT_FW");
1348         if (k >= 0)
1349         {
1350             j = adr2idx(fw, func_names[j].val);
1351             int i;
1352             for (i=j+1; i<j+100; i++)
1353             {
1354                 if (isBL(fw,i) && isBL(fw,i+2))
1355                 {
1356                     // find call to StopWDT_FW
1357                     uint32_t fadr = followBranch(fw, idx2adr(fw, i), 0x01000001);
1358                     if (func_names[k].val == fadr)
1359                     {
1360                         fadr = followBranch(fw, idx2adr(fw, i+2), 0x01000001);
1361                         fwAddMatch(fw,fadr,32,0,122);
1362                         return 1;
1363                     }
1364                 }
1365             }
1366         }
1367     }
1368 
1369     return 0;
1370 }
1371 
1372 // Special case for 'add_ptp_handler'
1373 int find_add_ptp_handler(firmware *fw, __attribute__ ((unused))string_sig *sig, int k)
1374 {
1375     uint32_t vals[] = { 0x9801, 0x9802, 0x9803, 0x9804, 0x9805, 0 };
1376     uint32_t fadr = 0;
1377 
1378     int i = 0;
1379     while ((vals[i] != 0) && isLDR_PC(fw,k) && (fwRd(fw,k) == 0) && (LDR2val(fw,k) == vals[i]))
1380     {
1381         k = find_inst(fw, isBL, k+1, 5);
1382         if (k == -1) return 0;
1383         if (fadr == 0)
1384             fadr = followBranch(fw, idx2adr(fw,k), 0x01000001);
1385         k = find_inst(fw, isLDR_PC, k+1, 5);
1386         i++;
1387         if (k == -1 && vals[i] != 0) return 0;
1388     }
1389 
1390     if (fadr != 0)
1391     {
1392         fwAddMatch(fw,fadr,32,0,121);
1393         return 1;
1394     }
1395 
1396     return 0;
1397 }
1398 
1399 // Special case for 'PT_PlaySound'
1400 int find_PT_PlaySound(firmware *fw)
1401 {
1402     int j, k;
1403     int k1 = get_saved_sig(fw,"LogCameraEvent");
1404 
1405     if (k1 >= 0)
1406     {
1407         j = find_str_ref(fw,"BufAccBeep");
1408         if (j >= 0)
1409         {
1410             k = find_inst(fw, isBL, j+1, 4);
1411             if (k >= 0)
1412             {
1413                 uint32_t fadr = followBranch(fw, idx2adr(fw,k), 0x01000001);
1414                 if (func_names[k1].val == fadr)
1415                 {
1416                     k = find_inst(fw, isB, k+1, 10);
1417                     fadr = followBranch(fw, idx2adr(fw, k), 1);
1418                     fwAddMatch(fw,fadr,32,0,122);
1419                     return 1;
1420                 }
1421             }
1422         }
1423     }
1424 
1425     return 0;
1426 }
1427 
1428 // Special case for 'getImageDirName'
1429 int find_getImageDirName(firmware *fw)
1430 {
1431     int k = find_str_ref(fw,"%3d_%02d%02d");
1432     if (k >= 0)
1433     {
1434         k = find_inst_rev(fw, isLDMFD_PC, k-1, 16);
1435         if (k >= 0)
1436         {
1437             uint32_t fadr = idx2adr(fw,k+1);
1438             fwAddMatch(fw,fadr,32,0,122);
1439             return 1;
1440         }
1441     }
1442     else
1443     {
1444         k = find_str_ref(fw,"___%02d");
1445         if (k >= 0)
1446         {
1447             k = find_inst_rev(fw, isLDMFD_PC, k-1, 18);
1448             if (k >= 0)
1449             {
1450                 if (isMOV(fw,k+1) && isMOV(fw,k+2)) // sanity check
1451                 {
1452                     uint32_t fadr = idx2adr(fw,k+1);
1453                     fwAddMatch(fw,fadr,32,0,122);
1454                     return 1;
1455                 }
1456             }
1457         }
1458     }
1459 
1460     return 0;
1461 }
1462 
1463 // Special case for 'GetImageFolder'
1464 uint32_t strGIF = 0;
1465 int match_GetImageFolder(firmware *fw, int k, uint32_t a_getImageDirName, uint32_t a_TakeSemaphore)
1466 {
1467     int k1, fnd;
1468 
1469     if (isBL(fw,k))
1470     {
1471         uint32_t fadr = followBranch2(fw,idx2adr(fw,k),0x01000001);
1472         if (fadr == a_getImageDirName)
1473         {
1474             int s = find_inst_rev(fw, isSTMFD_LR, k-1, 80);
1475             int e = find_inst(fw, isLDMFD_PC, k+1, 80);
1476             if ((s >= 0) && (e >= 0))
1477             {
1478                 fnd = 0;
1479                 for (k1=s+1; k1<k-1; k1++)
1480                 {
1481                     if (isBL(fw,k1))
1482                     {
1483                         fadr = followBranch2(fw,idx2adr(fw,k1),0x01000001);
1484                         if (fadr == a_TakeSemaphore)
1485                         {
1486                             fnd++;
1487                             break;
1488                         }
1489                     }
1490                 }
1491                 if (fnd != 0)
1492                 {
1493                     for (k1=k+1; k1<e-1; k1++)
1494                     {
1495                         if ((isLDR_PC(fw,k1) || isADR_PC(fw,k1)) && (idx2adr(fw,k1) == strGIF))
1496                         {
1497                             fnd--;
1498                             break;
1499                         }
1500                     }
1501                 }
1502                 if (fnd != 0)
1503                 {
1504                     fwAddMatch(fw,idx2adr(fw,s),32,0,122);
1505                     return 1;
1506                 }
1507             }
1508         }
1509     }
1510     return 0;
1511 }
1512 int find_GetImageFolder(firmware *fw)
1513 {
1514     int j = find_str_ref(fw,"GetCameraObjectTmpPath ERROR[ID:%lx] [TRY:%lx]\n");
1515     if (j < 0)
1516         j = find_str_ref(fw,"_GetCameraObjectTmpPath ERROR[ID:%lx] [TRY:%lx]\n");
1517     if (j >= 0)
1518     {
1519         strGIF = idx2adr(fw,j);
1520         int j = get_saved_sig(fw,"TakeSemaphore");
1521         int k = get_saved_sig(fw,"getImageDirName");
1522         if ((k >= 0) && (j >= 0))
1523         {
1524             return search_fw(fw, match_GetImageFolder, func_names[k].val, func_names[j].val, 1);
1525         }
1526     }
1527 
1528     return 0;
1529 }
1530 
1531 // Special case for 'GetDrive_ClusterSize'
1532 int match_GetDrive_ClusterSize(firmware *fw, int k, uint32_t v1, __attribute__ ((unused))uint32_t v2)
1533 {
1534     if (isBL_cond(fw,k))
1535     {
1536         uint32_t fadr = followBranch2(fw,idx2adr(fw,k),0xF1000001);
1537         if (fadr == v1)
1538         {
1539             int fnd = 0;
1540             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))
1541             {
1542                 fnd = 1;
1543             }
1544             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))
1545             {
1546                 fnd = 1;
1547             }
1548             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))
1549             {
1550                 fnd = 1;
1551             }
1552             else if (isADR_PC_cond(fw,k-1) && (strcmp(adr2ptr(fw,ADR2adr(fw,k-1)),"Mounter.c") == 0))
1553             {
1554                 fnd = 1;
1555             }
1556             else if (isADR_PC_cond(fw,k-2) && (strcmp(adr2ptr(fw,ADR2adr(fw,k-2)),"Mounter.c") == 0))
1557             {
1558                 fnd = 1;
1559             }
1560             if ((fnd == 1) &&
1561                 isLDR_PC(fw,k+1) &&
1562                 ((fwval(fw,k+2) & 0xFFF00FF0) == 0xE0800200) && ((fwval(fw,k+3) & 0xFFF00FF0) == 0xE0800100) &&
1563                 (fwval(fw,k+4) == 0xE5901004) && (fwval(fw,k+5) == 0xE5900008) && (fwval(fw,k+6) == 0xE0000091) &&
1564                 isLDMFD_PC(fw,k+7))
1565             {
1566                 k = find_inst_rev(fw,isSTMFD_LR,k-1,8);
1567                 if (k >= 0)
1568                 {
1569                     if (fwval(fw,k-1) == 0xE3500001)    // CMP R0, #1
1570                         k--;
1571                     fwAddMatch(fw,idx2adr(fw,k),32,0,122);
1572                     return 1;
1573                 }
1574             }
1575         }
1576     }
1577 
1578     return 0;
1579 }
1580 int find_GetDrive_ClusterSize(firmware *fw)
1581 {
1582     int k = get_saved_sig(fw,"DebugAssert");
1583     if (k >= 0)
1584     {
1585         return search_fw(fw, match_GetDrive_ClusterSize, func_names[k].val, 0, 16);
1586     }
1587 
1588     return 0;
1589 }
1590 
1591 int find_GetDrive_TotalClusters(firmware *fw)
1592 {
1593     extern uint32_t find_str_bytes(firmware *fw, char *str);
1594     // restrict usage (we rely on a function preceding a string)
1595     if (fw->dryos_ver < 52)
1596         return 0;
1597     uint32_t j = find_str_bytes(fw,"DriveLetterManager.c");
1598     if (j > 0)
1599     {
1600         int k = adr2idx(fw,j);
1601         k = find_inst_rev(fw,isLDMFD_PC,k-1,2);
1602         if ((k > 0) && ( (fwval(fw,k-1)&0xfffff0f0)==0xe0810090 )) // umull r0, r1, rx, ry
1603         {
1604             if (isBL(fw,k-2))
1605             {
1606                 k = idxFollowBranch(fw,k-2,0x01000001);
1607                 fwAddMatch(fw,idx2adr(fw,k),32,0,122);
1608                 return 1;
1609             }
1610         }
1611     }
1612 
1613     return 0;
1614 }
1615 
1616 // Special case for srand
1617 int find_srand(firmware *fw)
1618 {
1619     int k = get_saved_sig(fw,"rand");
1620     if (k >= 0)
1621     {
1622         k = adr2idx(fw, func_names[k].val) - 3;
1623         if (isLDR_PC(fw,k) && isSTR(fw,k+1) && isBX_LR(fw,k+2))
1624             fwAddMatch(fw,idx2adr(fw,k),32,0,122);
1625     }
1626 
1627     return 0;
1628 }
1629 
1630 int find_malloc_strictly(firmware *fw)
1631 {
1632 
1633     int s1 = find_str(fw,"Size: %ld");
1634     int s2 = find_str(fw,"Memory.c");
1635     int f1 = get_saved_sig(fw,"malloc");
1636     if ((s1 < 0)||(s2 < 0)||(f1 < 0))
1637         return 0;
1638     if (s1 < s2-16) // the two strings should be close
1639         s1 = find_Nth_str(fw,"Size: %ld",2); // this string has multiple instances, try the next one
1640     f1 = adr2idx(fw, func_names[f1].val);
1641 
1642     int r1 = find_nxt_str_ref(fw, s1, 0);
1643     int r2 = find_nxt_str_ref(fw, s2, 0);
1644     int l1 = 0;
1645     while((r1>0) && (r2>0) && (l1<2))
1646     {
1647         if (r2 == r1 + 3)
1648         {
1649             int m1 = find_inst_rev(fw,isBL,r1,6);
1650             if (m1 > 0)
1651             {
1652                 int m2 = idxFollowBranch(fw,m1,0x01000001);
1653                 if (m2 == f1)
1654                 {
1655                     m1 = find_inst_rev(fw,isSTMFD_LR,m1,3);
1656                     if (m1 > 0)
1657                     {
1658                         fwAddMatch(fw,idx2adr(fw,m1),32,0,122);
1659                         return 1;
1660                     }
1661                 }
1662             }
1663         }
1664         r1 = find_nxt_str_ref(fw, s1, r1+1);
1665         r2 = find_nxt_str_ref(fw, s2, r2+1);
1666         l1++;
1667     }
1668     return 0;
1669 }
1670 
1671 static int idx_createdialogbox=-1, idx_displaydialogbox=-1, idx_adduitodialog=-1, idx_getstring=-1;
1672 
1673 int find_DisplayBusyOnScreen(firmware *fw)
1674 {
1675 
1676     int s1 = find_str(fw,"ErrorMessageController.c");
1677     int s2 = find_str(fw,"StrMan.c");
1678     if (s1 < 0)
1679         s1 = find_str(fw,"MessageController.c");
1680     int j = find_str_ref(fw,"_PBBusyScrn");
1681     if (j < 0)
1682         j = find_str_ref(fw,"_PlayBusyScreen");
1683 
1684     if ((j>=0)&&(s1>=0)&&(s2>=0))
1685     {
1686         int m1 = find_Nth_inst(fw,isBL,j+1,12,fw->dryos_ver<54?4:fw->dryos_ver==59?2:3);
1687         int m2, k;
1688 
1689         if (fw->dryos_ver == 58)
1690         {
1691             // 1st B after str ref branches to DisplayBusyOnScreen
1692             m1 = find_inst(fw,isB,j+1,12);
1693             if (m1 > 0)
1694             {
1695                 m2 = idxFollowBranch(fw,m1,0x00000001);
1696                 k = find_nxt_str_ref(fw, s1, m2);
1697             }
1698             else
1699             {
1700                 return 0;
1701             }
1702         }
1703         else if (fw->dryos_ver == 57)
1704         {
1705             // these functions are called indirectly in this part of fw on r57
1706             int found = 0;
1707             for (k=-1; k>-3; k--)
1708             {
1709                 if ((fwval(fw,m1+k) & 0xFE1FF000) == 0xE41F0000) // ldr r0, =func
1710                 {
1711                     uint32_t u1 = LDR2val(fw, m1+k);
1712                     if ( u1 > fw->base )
1713                     {
1714                         if (isSTMFD_LR(fw, adr2idx(fw, u1)))
1715                         {
1716                             found = 1;
1717                             m2 = adr2idx(fw, u1);
1718                             k = find_nxt_str_ref(fw, s1, m2);
1719                             break;
1720                         }
1721                     }
1722                 }
1723             }
1724             if (!found)
1725             {
1726                 return 0;
1727             }
1728         }
1729         else
1730         {
1731             m2 = idxFollowBranch(fw,m1,0x01000001);
1732             k = find_nxt_str_ref(fw, s1, m2);
1733             if ((k <= 0)||(k-m2 >= 22))
1734             {
1735                 // not found, try the next BL
1736                 m1 = find_inst(fw,isBL,m1+1,4);
1737                 m2 = idxFollowBranch(fw,m1,0x01000001);
1738                 k = find_nxt_str_ref(fw, s1, m2);
1739             }
1740         }
1741 
1742 
1743         if ((k > 0)&&(k-m2 < 22))
1744         {
1745             // the string is referenced near enough
1746             idx_createdialogbox = find_inst_rev(fw, isBL, k-1, 4);
1747             // DisplayBusyOnScreen is found
1748             fwAddMatch(fw,idx2adr(fw,m2),32,0,122);
1749             // find additional stuff
1750             idx_adduitodialog = find_inst(fw, isBL, k+1, 7);
1751             int m3;
1752             for (m3=k; m3<k+128; m3++)
1753             {
1754                 // mov r0, #imm or ldr r0, [pc,... between two BLs
1755                 if (isBL(fw,m3)&&isBL(fw,m3+2)&&
1756                     (((fwval(fw,m3+1)&0xfffff000)==0xe3a00000)||((fwval(fw,m3+1)&0xff7ff000)==0xe51f0000)))
1757                 {
1758                     // further check
1759                     int m30 = m3+2;
1760                     int m4 = idxFollowBranch(fw,m30,0x01000001);
1761                     if (m4 > 0)
1762                     {
1763                         // search for ref. to assert string
1764                         int m5 = find_inst(fw, isLDMFD_PC, m4+1, 64);
1765                         int m6 = find_nxt_str_ref(fw, s2, m4);
1766                         if ((m6 > 0)&&(m6 < m5))
1767                         {
1768                             idx_getstring = m30;
1769                             break;
1770                         }
1771                         // no string, search for reference to 0x00000020 (string consisting of a single space char)
1772                         m5 = find_inst(fw, isADR_PC, m4+1, 10);
1773                         if (m5>0)
1774                         {
1775                             uint32_t u1 = ADR2adr(fw, m5);
1776                             if (fwval(fw, adr2idx(fw, u1)) == 0x00000020)
1777                             {
1778                                 idx_getstring = m30;
1779                                 break;
1780                             }
1781                         }
1782                     }
1783                 }
1784             }
1785             if (fw->dryos_ver < 54)
1786             {
1787                 m3 = find_inst(fw, isLDMFD_PC, k+30, 64);
1788                 if (m3>0)
1789                 {
1790                     m3 = find_Nth_inst_rev(fw, isBL, m3-1, 8, 2);
1791                     if (m3>0)
1792                     {
1793                         idx_displaydialogbox = m3;
1794                     }
1795                 }
1796             }
1797             else
1798             {
1799                 m3 = find_inst(fw, isLDMFD, k+30, 20);
1800                 if (m3>0)
1801                 {
1802                     m3 = find_inst_rev(fw, isBL, m3-1, 4);
1803                     if (m3>0)
1804                     {
1805                         idx_displaydialogbox = m3;
1806                     }
1807                 }
1808             }
1809             return 1;
1810         }
1811     }
1812 
1813     return 0;
1814 }
1815 
1816 int find_UndisplayBusyOnScreen(firmware *fw)
1817 {
1818     if (get_saved_sig(fw,"DisplayBusyOnScreen") < 0) return 0;
1819     int j;
1820     if (fw->dryos_ver > 57)
1821     {
1822         j = find_str_ref(fw,"_PBBusyScrnToCtrlSrvTask");
1823     }
1824     else
1825     {
1826         j = find_str_ref(fw,"_PBBusyScrn");
1827     }
1828     if (j < 0)
1829         j = find_str_ref(fw,"_PlayBusyScreen");
1830 
1831     if (fw->dryos_ver < 57)
1832     {
1833         if (idx_createdialogbox > 0)
1834         {
1835             int m;
1836             for (m=0; m<2; m++)
1837             {
1838                 int n = find_Nth_inst(fw, isSTMFD_LR, idx_createdialogbox + 30, 140, m+1);
1839                 if (n>0)
1840                 {
1841                     uint32_t a1 = idx2adr(fw,n);
1842                     if (j > 0)
1843                     {
1844                         int k;
1845                         for (k=j; k<j+24; k++)
1846                         {
1847                             if (isBL_cond(fw,k)&&(idx2adr(fw,idxFollowBranch(fw,k,0xe1000001))==a1)) // BLEQ
1848                             {
1849                                 fwAddMatch(fw,a1,32,0,122);
1850                                 return 1;
1851                             }
1852                         }
1853                     }
1854                 }
1855             }
1856         }
1857     }
1858     else
1859     {
1860         int m1 = find_Nth_inst(fw,isBLEQ,j+1,20,1);
1861         if (m1 > 0)
1862         {
1863             // these functions are called indirectly in this part of fw on r57+
1864             int k;
1865             for (k=-1; k>-3; k--)
1866             {
1867                 if ((fwval(fw,m1+k) & 0xFE1FF000) == 0x041F0000) // ldreq r0, =func
1868                 {
1869                     uint32_t u1 = LDR2val(fw, m1+k);
1870                     if ( u1 > fw->base )
1871                     {
1872                         if (isSTMFD_LR(fw, adr2idx(fw, u1)))
1873                         {
1874                             fwAddMatch(fw,u1,32,0,122);
1875                             return 1;
1876                         }
1877                     }
1878                 }
1879             }
1880         }
1881     }
1882     return 0;
1883 }
1884 // TODO: redundant functions follow
1885 int find_CreateDialogBox(firmware *fw)
1886 {
1887     if (get_saved_sig(fw,"DisplayBusyOnScreen") < 0) return 0;
1888     if (idx_createdialogbox > 0)
1889     {
1890         int n = idxFollowBranch(fw,idx_createdialogbox,0x01000001);
1891         if (n>0)
1892         {
1893             fwAddMatch(fw,idx2adr(fw,n),32,0,122);
1894             return 1;
1895         }
1896     }
1897     return 0;
1898 }
1899 int find_DisplayDialogBox(firmware *fw)
1900 {
1901     if (get_saved_sig(fw,"DisplayBusyOnScreen") < 0) return 0;
1902     if (idx_displaydialogbox > 0)
1903     {
1904         int n = idxFollowBranch(fw,idx_displaydialogbox,0x01000001);
1905         if (n>0)
1906         {
1907             fwAddMatch(fw,idx2adr(fw,n),32,0,122);
1908             return 1;
1909         }
1910     }
1911     return 0;
1912 }
1913 int find_add_ui_to_dialog(firmware *fw)
1914 {
1915     if (get_saved_sig(fw,"DisplayBusyOnScreen") < 0) return 0;
1916     if (idx_adduitodialog > 0)
1917     {
1918         int n = idxFollowBranch(fw,idx_adduitodialog,0x01000001);
1919         if (n>0)
1920         {
1921             fwAddMatch(fw,idx2adr(fw,n),32,0,122);
1922             return 1;
1923         }
1924     }
1925     return 0;
1926 }
1927 int find_get_string_by_id(firmware *fw)
1928 {
1929     if (get_saved_sig(fw,"DisplayBusyOnScreen") < 0) return 0;
1930     if (idx_getstring > 0)
1931     {
1932         int n = idxFollowBranch(fw,idx_getstring,0x01000001);
1933         if (n>0)
1934         {
1935             fwAddMatch(fw,idx2adr(fw,n),32,0,122);
1936             return 1;
1937         }
1938     }
1939     return 0;
1940 }
1941 
1942 int find_get_self_task_errno_pointer(firmware *fw)
1943 {
1944     int f1 = get_saved_sig(fw,"malloc");
1945     int f2 = get_saved_sig(fw,"close");
1946     if ((f1<0) && (f2<0))
1947         return 0;
1948     f1 = adr2idx(fw, func_names[f1].val);
1949     f1 = find_inst(fw, isLDMFD_PC, f1, 24);
1950     if (f1>0)
1951     {
1952         f1 = find_inst_rev(fw, isBL, f1, 6);
1953         if (f1>0)
1954         {
1955             if (fwval(fw,f1+2) == 0xe5801000) // str r1, [r0]
1956             {
1957                 f1 = idxFollowBranch(fw,f1,0x01000001);
1958                 fwAddMatch(fw,idx2adr(fw,f1),32,0,122);
1959                 return 1;
1960             }
1961         }
1962     }
1963     // older cams don't set errno on malloc failure
1964     f1 = adr2idx(fw, func_names[f2].val);
1965     f1 = find_Nth_inst(fw, isBL, f1, 8, 2); // second BL
1966     if (f1>0)
1967     {
1968         if (fwval(fw,f1+2) == 0xe5801000) // str r1, [r0]
1969         {
1970             f1 = idxFollowBranch(fw,f1,0x01000001);
1971             fwAddMatch(fw,idx2adr(fw,f1),32,0,122);
1972             return 1;
1973         }
1974     }
1975     return 0;
1976 }
1977 
1978 int find_get_nd_value(firmware *fw)
1979 {
1980 
1981     int f1 = get_saved_sig(fw,"PutInNdFilter_FW");
1982     int f2 = get_saved_sig(fw,"ClearEventFlag");
1983     int f3 = find_saved_sig("get_nd_value");
1984     if ((f3 >= 0) && (func_names[f3].val != 0)) // return if func already found
1985         return 0;
1986     if ((f1 < 0) || (f2 < 0))
1987         return 0;
1988     f1 = adr2idx(fw, func_names[f1].val);
1989     f2 = adr2idx(fw, func_names[f2].val);
1990     int k1 = find_Nth_inst(fw,isBL,f1,10,2);
1991     int k2 = find_inst(fw,isBL,f1,6);
1992     if ((k1 == -1) || (k2 == -1))
1993         return 0;
1994     // note for the following line: same address can have different index on cams with multiple fw regions
1995     // followBranch2 is for veneer support (s110)
1996     if ( followBranch2(fw,idx2adr(fw,k2),0x01000001) != idx2adr(fw,f2) ) // ClearEventFlag?
1997         return 0;
1998     k1 = idxFollowBranch(fw,k1,0x01000001); // PutInNdFilter_low
1999     k2 = find_inst(fw,isBL,k1,6);
2000     if (k2 == -1)
2001         return 0;
2002     // check for signs of other functions (GetUsableAvRange, etc)
2003     int k3;
2004     int k4 = 0;
2005     for (k3=k2-1;k3>k2-3;k3--)
2006     {
2007         uint32_t v1 = fwval(fw, k3);
2008         k4 += (v1 == 0xe28d0004)?1:(v1 == 0xe1a0100d)?4: // add r0,sp,#4 ; mov r1,sp - GetUsableAvRange
2009               ((v1 & 0xffffff00) == 0xe3a00000)?0x10:0; // mov r0, #small_imm - sx400
2010     }
2011     if (k4 == 0) // probably get_nd_value
2012     {
2013         k2 = idxFollowBranch(fw,k2,0x01000001);
2014         fwAddMatch(fw,idx2adr(fw,k2),32,0,122);
2015         return 1;
2016     }
2017 
2018     return 0;
2019 }
2020 
2021 // for cams with both ND and iris
2022 int find_get_current_nd_value_iris(firmware *fw)
2023 {
2024     // match is only for cams with both, task is mostly a good indicator
2025     if(get_saved_sig(fw,"task_Nd") < 0 || get_saved_sig(fw,"task_IrisEvent") < 0) {
2026         return 0;
2027     }
2028     int f1 = get_saved_sig(fw,"get_current_exp");
2029     if(f1 < 0)
2030         return 0;
2031 
2032     f1 = adr2idx(fw, func_names[f1].val);
2033     int blcnt, i;
2034     // expect
2035     // bleq DebugAssert
2036     // followed by 5 bl with other instruction between
2037     // looking for 5th
2038     for(i=0, blcnt=0; i<16 && blcnt < 7; i++) {
2039         if(!blcnt) {
2040             if(isBL_cond(fw,f1+i)) {
2041                 blcnt++;
2042             } else if(isBL(fw,f1+i)) {
2043                 return 0;
2044             }
2045             continue;
2046         }
2047         if(!isBL(fw,f1+i)) {
2048             continue;
2049         }
2050         blcnt++;
2051         if(blcnt == 6) {
2052             int f2 = idxFollowBranch(fw,f1+i,0x01000001);
2053             // non-ND cameras have a call to return 0
2054             if(isMOV(fw,f2) && (fwRd(fw,f2) == 0) && (fwOp2(fw,f2) == 0)) // MOV R0, 0
2055                 return 0;
2056             // veneer (might be better to require veneer)
2057             if(isB(fw,f2)) {
2058                 f2 = idxFollowBranch(fw,f2,0x00000001);
2059             }
2060             fwAddMatch(fw,idx2adr(fw,f2),32,0,122);
2061             return 1;
2062         }
2063     }
2064     return 0;
2065 }
2066 
2067 int find_get_current_nd_value(firmware *fw)
2068 {
2069 
2070     // string only present on ND-only cameres
2071     if(find_str(fw, "IrisSpecification.c") < 0) {
2072         return find_get_current_nd_value_iris(fw);
2073     }
2074 
2075     int f1 = get_saved_sig(fw,"GetCurrentAvValue");
2076     if(f1 < 0)
2077         return 0;
2078 
2079     f1 = adr2idx(fw, func_names[f1].val);
2080     // expect
2081     // adreq r0, "IrisController.c"
2082     // bleq DebugAssert
2083     // bl j_get_current_nd_value
2084     int sadr = find_str(fw, "IrisController.c");
2085     int j = find_nxt_str_ref(fw, sadr, f1);
2086     if (j < 0)
2087         return 0;
2088 
2089     if(isBL_cond(fw,j+1) && isBL(fw,j+2)) {
2090         f1 = idxFollowBranch(fw,j+2,0x01000001);
2091         // veneer
2092         if(isB(fw,f1)) {
2093             f1 = idxFollowBranch(fw,f1,0x00000001);
2094         }
2095         fwAddMatch(fw,idx2adr(fw,f1),32,0,122);
2096         return 1;
2097     }
2098 
2099     return 0;
2100 }
2101 
2102 // get live view "DeltaSV" value
2103 int find_get_current_deltasv(firmware *fw)
2104 {
2105     int f1 = get_saved_sig(fw,"get_current_exp");
2106     if(f1 < 0)
2107         return 0;
2108 
2109     f1 = adr2idx(fw, func_names[f1].val);
2110     int blcnt, i;
2111     // expect
2112     // bleq DebugAssert
2113     // followed by at least 3 bl with other instructions between
2114     // looking for 3rd
2115     for(i=0, blcnt=0; i<16 && blcnt < 4; i++) {
2116         if(!blcnt) {
2117             if(isBL_cond(fw,f1+i)) {
2118                 blcnt++;
2119             } else if(isBL(fw,f1+i)) {
2120                 return 0;
2121             }
2122             continue;
2123         }
2124         if(!isBL(fw,f1+i)) {
2125             continue;
2126         }
2127         blcnt++;
2128         if(blcnt == 4) {
2129             int f2 = idxFollowBranch(fw,f1+i,0x01000001);
2130             // veneer?
2131             if(isB(fw,f2)) {
2132                 f2 = idxFollowBranch(fw,f2,0x00000001);
2133             }
2134             fwAddMatch(fw,idx2adr(fw,f2),32,0,122);
2135             return 1;
2136         }
2137     }
2138     return 0;
2139 }
2140 
2141 
2142 int find_getcurrentmachinetime(firmware *fw)
2143 {
2144     int f1 = get_saved_sig(fw,"SetHPTimerAfterTimeout");
2145     if (f1 < 0)
2146         return 0;
2147     f1 = adr2idx(fw, func_names[f1].val);
2148     f1 = find_inst(fw, isBL, f1, 16);
2149     if (f1>0)
2150     {
2151         f1 = idxFollowBranch(fw,f1,0x01000001);
2152         fwAddMatch(fw,idx2adr(fw,f1),32,0,122);
2153         return 1;
2154     }
2155     return 0;
2156 }
2157 
2158 // for cases where method 15 fails (sx170)
2159 int find_sethptimeraftertimeout(firmware *fw)
2160 {
2161     int sadr = find_str(fw, "FrameRateGenerator.c");
2162     int j = find_nxt_str_ref(fw, sadr, -1);
2163     if (j < 0)
2164         return 0;
2165     int f1, f2, n;
2166     for (n=0; n<2; n++)
2167     {
2168         f1 = find_inst_rev(fw, isBL, j-1, 7);
2169         f2 = find_Nth_inst_rev(fw, isBL, j-1, 128, 2);
2170         // check whether previous BL is too close
2171         if ((f1 < 1) || (f1-f2<8))
2172         {
2173             j = find_nxt_str_ref(fw, sadr, j+1);
2174             if (j < 0)
2175                 return 0;
2176         }
2177         else
2178         {
2179             f1 = idxFollowBranch(fw,f1,0x01000001);
2180             fwAddMatch(fw,idx2adr(fw,f1),32,0,122);
2181             return 1;
2182         }
2183     }
2184     return 0;
2185 }
2186 
2187 uint32_t frsp_buf = 0;
2188 uint32_t frsp_buf_at = 0;
2189 int frsp_param = -1;
2190 int frsp_argcnt = 0;
2191 int find_DoMovieFrameCapture(firmware *fw)
2192 {
2193     void add_func_name(char*, uint32_t, char*);
2194     // we need the uncached bit
2195     int match_CAM_UNCACHED_BIT(firmware*, int, int);
2196     search_saved_sig(fw, "FreeUncacheableMemory", match_CAM_UNCACHED_BIT, 0, 0, 8);
2197 
2198     int j = get_saved_sig(fw,"SetImageMode");
2199     if (j < 0)
2200         return 0;
2201     j = adr2idx(fw, func_names[j].val);
2202     int k = 0;
2203     int k1 = 0;
2204     int l = j + 20;
2205     while (j < l)
2206     {
2207         j = find_inst(fw, isBL, j+1, 20);
2208         if (j == -1)
2209             break;
2210         int j1 = idxFollowBranch(fw,j,0x01000001);
2211         if (j != j1)
2212         {
2213             int j2;
2214             for (j2=j1; j2<j1+6; j2++)
2215             {
2216                 if ((fwval(fw,j2) & 0xFF000000) == 0x1A000000) // bne
2217                 {
2218                     int j3 = idxFollowBranch(fw,j2,0xF1000001);
2219                     if (j3-j2>0 && j3-j2<5)
2220                     {
2221                         if (isBL(fw,j3))
2222                         {
2223                             // buffer adr is embedded in routine, evaluate later
2224                             k = idxFollowBranch(fw,j3,0x01000001);
2225                             fwAddMatch(fw,idx2adr(fw,k),32,0,122);
2226                             // add_func_name("DoMovieFrameCapture_helper1", idx2adr(fw,k), ""); // for visual verification
2227                             k1 = 1;
2228                             break;
2229                         }
2230                         else
2231                         {
2232                             // buffer and param are func args, evaluate here
2233                             int m = 0;
2234                             while (m < 4)
2235                             {
2236                                 if ((fwval(fw,j3+m) & 0xFE1F0000) == 0xE41F0000) // ldr rx,
2237                                 {
2238                                     frsp_argcnt = fwRd(fw,j3+m) + 1; // this should be loaded in the right register directly
2239                                     frsp_buf = LDR2val(fw,j3+m);
2240                                     frsp_buf_at = idx2adr(fw,j3+m);
2241                                     if (!((frsp_buf > fw->uncached_adr) &&
2242                                           (fw->uncached_adr+fw->maxram))) // has to be uncached ram
2243                                         frsp_buf = 0;
2244                                 }
2245                                 if ((fwval(fw,j3+m) & 0xFFF00000) == 0xE3A00000) // mov rx,
2246                                 {
2247                                     uint32_t u1 = ALUop2a(fw,j3+m);
2248                                     if (u1>fw->uncached_adr && u1<(fw->uncached_adr+fw->maxram))
2249                                     {
2250                                         frsp_buf = u1;
2251                                         frsp_buf_at = idx2adr(fw,j3+m);
2252                                         frsp_argcnt = fwRd(fw,j3+m) + 1; // this should be loaded in the right register directly
2253                                     }
2254                                     else
2255                                     {
2256                                         frsp_param = u1;
2257                                     }
2258                                 }
2259                                 if (isBL(fw,j3+m))
2260                                 {
2261                                     k = idxFollowBranch(fw,j3+m,0x01000001);
2262                                     fwAddMatch(fw,idx2adr(fw,k),32,0,122);
2263                                     // add_func_name("DoMovieFrameCapture_helper2", idx2adr(fw,j1), ""); // for visual verification
2264                                     break;
2265                                 }
2266                                 m++;
2267                             }
2268                             if (k)
2269                                 break;
2270                         }
2271                     }
2272                 }
2273             }
2274             if (k)
2275                 break;
2276         }
2277     }
2278     if (k && k1)
2279     {
2280         k1 = k+1;
2281         while (k1>0 && k1<k+20)
2282         {
2283             if (isLDR_PC(fw,k1))
2284             {
2285                 uint32_t v = LDR2val(fw,k1);
2286                 if (v>fw->uncached_adr && v<fw->uncached_adr+fw->maxram && (v&3)==0)
2287                 {
2288                     frsp_buf = v;
2289                     frsp_param = 0;
2290                     frsp_buf_at = idx2adr(fw,k1);
2291                     break;
2292                 }
2293             }
2294             k1++;
2295         }
2296     }
2297     if (k)
2298         return 1;
2299     return 0;
2300 }
2301 
2302 int find_get_ptp_buf_size(firmware *fw)
2303 {
2304     int j = get_saved_sig(fw,"handle_PTP_OC_SendObject"); // same handler as CANON_SendObjectByPath
2305     if(j < 0) {
2306         // fprintf(stderr,"find_get_ptp_buf_size missing handle_PTP_OC_SendObject\n");
2307         return 0;
2308     }
2309     int k=adr2idx(fw,func_names[j].val);
2310     int k_max=k+80;
2311     uint32_t adr=0;
2312     uint32_t file_buf_id=get_ptp_file_buf_id(fw);
2313 
2314     for(; k < k_max;k++) {
2315         // look for
2316         // mov r0,#file_buf_id
2317         // bl ...
2318         if(isMOV_immed(fw,k) && fwRn(fw,k) == 0 && ALUop2(fw,k) == file_buf_id && isBL(fw, k+1)) {
2319             adr = followBranch(fw,idx2adr(fw,k+1),0x01000001);
2320             // fprintf(stderr,"find_get_ptp_buf_size match 1 0x%08x @0x%08x\n",adr,idx2adr(fw,k+1));
2321             break;
2322         }
2323     }
2324     if(!adr) {
2325         // fprintf(stderr,"find_get_ptp_buf_size no match\n");
2326         return 0;
2327     }
2328     // look for same seq again, within 6 ins
2329     k_max = k+6;
2330     for(; k < k_max;k++) {
2331         if(isMOV_immed(fw,k) && fwRn(fw,k) == 0 && ALUop2(fw,k) == file_buf_id && isBL(fw, k+1)) {
2332             uint32_t adr2 = followBranch(fw,idx2adr(fw,k+1),0x01000001);
2333             // is it the same address?
2334             if(adr2 == adr) {
2335                 // fprintf(stderr,"find_get_ptp_buf_size match 2 @0x%08x\n",idx2adr(fw,k+1));
2336                 fwAddMatch(fw,adr,32,0,122);
2337                 return 0;
2338             }
2339             // fprintf(stderr,"find_get_ptp_buf_size match 2 mismatch 0x%08x != 0x%08x @0x%08x\n",adr,adr2,idx2adr(fw,k+1));
2340         }
2341     }
2342     return 0;
2343 }
2344 
2345 int find_GetBaseSv(firmware *fw)
2346 {
2347     int j = get_saved_sig(fw,"SetPropertyCase");
2348     if (j < 0)
2349         return 0;
2350     j = adr2idx(fw, func_names[j].val);
2351 
2352     int sadr = find_str(fw, "Sensitive.c");
2353     if (sadr < fw->lowest_idx)
2354         return 0;
2355     int s1 = find_nxt_str_ref(fw, sadr, -1/*fw->lowest_idx*/);
2356     int hist[3] = {0, 0, 0};
2357     while (s1 >= 0)
2358     {
2359         hist[2] = hist[1];
2360         hist[1] = hist[0];
2361         hist[0] = s1;
2362         if (hist[0] && hist[1] && hist[2])
2363         {
2364             if ((hist[0]-hist[1]<6) && (hist[1]-hist[2]<7))
2365             {
2366                 int n;
2367                 for (n=s1+1; n<s1+26; n++)
2368                 {
2369                     if ( isBL(fw, n) )
2370                     {
2371                         int k;
2372                         k = idxFollowBranch(fw,n,0x01000001);
2373                         if ( idx2adr(fw, k) == idx2adr(fw, j) )
2374                         {
2375                             // SetPropertyCase call found
2376                             k = find_inst(fw, isBL, s1+2, 6);
2377                             if (k != -1)
2378                             {
2379                                 // first BL following BLEQ DebugAssert
2380                                 int l = idxFollowBranch(fw,k,0x01000001);
2381                                 if ( isB(fw, l) )
2382                                 {
2383                                     // in most cases there's a veneer (exception: sx1)
2384                                     void add_func_name(char*, uint32_t, char*);
2385                                     k = idxFollowBranch(fw,l,0x01000001);
2386                                     if ( isB(fw, k) )
2387                                     {
2388                                         int m = idxFollowBranch(fw,k,0x01000001);
2389                                         add_func_name("j_j_GetBaseSv", idx2adr(fw,l), "");
2390                                         add_func_name("j_GetBaseSv", idx2adr(fw,k), "");
2391                                         fwAddMatch(fw,idx2adr(fw,m),32,0,122);
2392                                     }
2393                                     else
2394                                     {
2395                                         add_func_name("j_GetBaseSv", idx2adr(fw,l), "");
2396                                         fwAddMatch(fw,idx2adr(fw,k),32,0,122);
2397                                     }
2398                                 }
2399                                 else
2400                                 {
2401                                     fwAddMatch(fw,idx2adr(fw,l),32,0,122);
2402                                 }
2403                                 return 1;
2404                             }
2405                         }
2406                     }
2407                 }
2408             }
2409         }
2410         s1 = find_nxt_str_ref(fw, sadr, s1+1);
2411     }
2412 
2413     return 0;
2414 }
2415 
2416 int find_Remove(firmware *fw)
2417 {
2418     int f1 = get_saved_sig(fw,"Close");
2419     if(f1 < 0)
2420         return 0;
2421 
2422     f1 = adr2idx(fw, func_names[f1].val);
2423     int f2, blcnt, i;
2424     f2 = find_str_ref(fw,"File Write Fail.");
2425     if(f2 == -1)
2426         return 0;
2427     // looking for 1st bl after Close
2428     for(i=1, blcnt=0; i<8 && blcnt < 2; i++) {
2429         if(!isBL(fw,f2+i)) {
2430             continue;
2431         }
2432         // is it Close?
2433         if(idxFollowBranch(fw,f2+i,0x01000001)==f1) {
2434             blcnt++;
2435             continue;
2436         }
2437         else if(idxFollowBranch(fw,idxFollowBranch(fw,f2+i,0x01000001),0x01000001)==f1) {
2438             blcnt++;
2439             continue;
2440         }
2441         if (blcnt == 1) {
2442             f2 = idxFollowBranch(fw,f2+i,0x01000001);
2443             fwAddMatch(fw,idx2adr(fw,f2),32,0,122);
2444             return 1;
2445         }
2446     }
2447     return 0;
2448 }
2449 
2450 int find_dispatch_funcs(firmware *fw, int param)
2451 {
2452     int f1;
2453     if (param==0) {
2454         f1= get_saved_sig(fw,"EnableDispatch_low");
2455     }
2456     else if (param==1) {
2457         f1= get_saved_sig(fw,"DisableDispatch_low");
2458     }
2459     else {
2460         return 0;
2461     }
2462     if(f1 < 0)
2463         return 0;
2464 
2465     f1 = adr2idx(fw, func_names[f1].val);
2466     int r0, r1, cnt;
2467     r0 = find_str(fw,"Booting"); // for sx230 (extra task on a few models)
2468     if (r0 == -1) {
2469         r0 = find_str(fw,"Startup"); // locating taskcreate_Startup
2470         r1 = find_str(fw,"Startup.c");
2471         if (r0 == r1) { // for s5is
2472             r0 = find_Nth_str(fw,"Startup",2);
2473         }
2474     }
2475     r0 = find_nxt_str_ref(fw,r0,r0-1024);
2476     if(r0 < 0)
2477         return 0;
2478     r0 = adr2idx(fw,idx2adr(fw,r0)); // needed on cams with code copied to RAM
2479     cnt = 0;
2480     while (r0!=-1 && cnt<5) {
2481         r0 = find_inst_rev(fw,isBL,r0-1,10);
2482         int b1 = idxFollowBranch(fw,r0,0x01000001);
2483         b1 = adr2idx(fw,idx2adr(fw,b1)); // needed on cams with code copied to RAM
2484         if (isLDR_PC(fw,b1)) { // for s110
2485             b1 = idxFollowBranch(fw,b1,0x01000001);
2486         }
2487         if (param==0) { // EnableDispatch
2488             r1 = find_nxt_str_ref_alt(fw, "KerSys.c", b1, 24);
2489             int i1 = find_inst(fw,isLDMFD_PC,b1,24);
2490             if (r1!=-1 && i1>r1) {
2491                 int j1 = find_Nth_inst(fw,isBL,b1,24,1);
2492                 if (j1 != -1) {
2493                     if (idx2adr(fw,idxFollowBranch(fw,j1,0x01000001))==idx2adr(fw,f1)) {
2494                         fwAddMatch(fw,idx2adr(fw,b1),32,0,122);
2495                         return 1;
2496                     }
2497                 }
2498             }
2499         }
2500         else if (param==1) { // DisableDispatch
2501             int c = 1;
2502             while (c<3) {
2503                 int b2 = find_Nth_inst(fw,isBL,b1,12,c);
2504                 if (b2 == -1) {
2505                     break;
2506                 }
2507                 b2 = idxFollowBranch(fw,b2,0x01000001);
2508                 b2 = adr2idx(fw,idx2adr(fw,b2)); // needed on cams with code copied to RAM
2509                 r1 = find_nxt_str_ref_alt(fw, "KerSys.c", b2, 24);
2510                 int i1 = find_inst(fw,isLDMFD_PC,b2,24);
2511                 if (r1!=-1 && i1>r1) {
2512                     int j1 = find_Nth_inst(fw,isBL,b2,24,1);
2513                     if (j1 != -1) {
2514                         if (idx2adr(fw,idxFollowBranch(fw,j1,0x01000001))==idx2adr(fw,f1)) {
2515                             fwAddMatch(fw,idx2adr(fw,b2),32,0,122);
2516                             return 1;
2517                         }
2518                     }
2519                 }
2520                 c++;
2521             }
2522         }
2523         cnt++;
2524     }
2525     return 0;
2526 }
2527 
2528 //------------------------------------------------------------------------------------------------------------
2529 
2530 // Data for matching the '_log' function
2531 uint32_t log_test[] = {
2532     0x1526E50E, 0x3FDBCB7B, 0
2533 };
2534 
2535 // Data for matching 'Fut' functions
2536 uint32_t DeleteDirectory_Fut_test[] = { 0x09400017 };
2537 uint32_t MakeDirectory_Fut_test[]   = { 0x09400015 };
2538 uint32_t RenameFile_Fut_test[]      = { 0x09400013 };
2539 
2540 //------------------------------------------------------------------------------------------------------------
2541 
2542 // Signature matching data
2543 string_sig string_sigs[] =
2544 {
2545     // Same as previously found eventproc - do these first
2546     {20, "AllocateMemory", "AllocateMemory_FW", 1 },
2547     {20, "Close", "Close_FW", 1 },
2548     {20, "CreateCountingSemaphore", "CreateCountingSemaphore_FW", 1 },
2549     {20, "CreateTask", "CreateTask_FW", 1 },
2550     {20, "DeleteSemaphore", "DeleteSemaphore_FW", 1 },
2551     {20, "DispCon_ShowBitmapColorBar", "DispCon_ShowBitmapColorBar_FW", 1 },
2552     {20, "ExitTask", "ExitTask_FW", 1 },
2553     {20, "Fclose_Fut", "Fclose_Fut_FW", 1 },
2554     {20, "Fopen_Fut", "Fopen_Fut_FW", 1 },
2555     {20, "Fread_Fut", "Fread_Fut_FW", 1 },
2556     {20, "FreeMemory", "FreeMemory_FW", 1 },
2557     {20, "Fseek_Fut", "Fseek_Fut_FW", 1 },
2558     {20, "Fwrite_Fut", "Fwrite_Fut_FW", 1 },
2559     {20, "GetSDProtect", "GetSDProtect_FW", 1 },
2560     {20, "GetSystemTime", "GetSystemTime_FW", 1 },
2561     {20, "GetCurrentAvValue", "GetCurrentAvValue_FW", 1 },
2562     {20, "GetCurrentShutterSpeed", "GetCurrentShutterSpeed_FW", 1 },
2563     {20, "GetUsableMaxAv", "GetUsableMaxAv_FW", 1 },
2564     {20, "GetUsableMinAv", "GetUsableMinAv_FW", 1 },
2565     {20, "GetOpticalTemperature", "GetOpticalTemperature_FW", 1 },
2566     {20, "GetVRAMHPixelsSize", "GetVRAMHPixelsSize_FW", 1 },
2567     {20, "GetVRAMVPixelsSize", "GetVRAMVPixelsSize_FW", 1 },
2568     {20, "GetZoomLensCurrentPoint", "GetZoomLensCurrentPoint_FW", 1 },
2569     {20, "GiveSemaphore", "GiveSemaphore_FW", 1 },
2570     {20, "GUISrv_StartGUISystem", "GUISrv_StartGUISystem_FW", 1 },
2571     {20, "LEDDrive", "LEDDrive_FW", 1 },
2572     {20, "LockMainPower", "LockMainPower_FW", 1 },
2573     {20, "lseek", "Lseek_FW", 1 },
2574     {20, "Lseek", "Lseek_FW", 1 },
2575     {20, "MoveIrisWithAv", "MoveIrisWithAv_FW", 1 },
2576     {20, "MoveZoomLensWithPoint", "MoveZoomLensWithPoint_FW", 1 },
2577     {20, "memcmp", "memcmp_FW", 1 },
2578     {20, "memcpy", "memcpy_FW", 1 },
2579     {20, "memset", "memset_FW", 1 },
2580     {20, "NewTaskShell", "NewTaskShell_FW", 1 },
2581     {20, "NR_GetDarkSubType", "NR_GetDarkSubType_FW", 1 },
2582     {20, "NR_SetDarkSubType", "NR_SetDarkSubType_FW", 1 },
2583     {20, "Open", "Open_FW", 1 },
2584     {20, "PostLogicalEventForNotPowerType", "PostLogicalEventForNotPowerType_FW", 1 },
2585     {20, "PostLogicalEventToUI", "PostLogicalEventToUI_FW", 1 },
2586     {20, "PT_MoveDigitalZoomToWide", "PT_MoveDigitalZoomToWide_FW", 1 },
2587     {20, "PT_MoveOpticalZoomAt", "PT_MoveOpticalZoomAt_FW", 1 },
2588     {20, "Read", "Read_FW", 1 },
2589     {20, "RefreshPhysicalScreen", "RefreshPhysicalScreen_FW", 1 },
2590     {20, "ResetFocusLens", "ResetFocusLens_FW", 1 },
2591     {20, "ResetZoomLens", "ResetZoomLens_FW", 1 },
2592     {20, "SavePaletteData", "SavePaletteData_FW", 1 },
2593     {20, "SetAutoShutdownTime", "SetAutoShutdownTime_FW", 1 },
2594     {20, "SetCurrentCaptureModeType", "SetCurrentCaptureModeType_FW", 1 },
2595     {20, "SetDate", "SetDate_FW", 1 },
2596     {20, "SetScriptMode", "SetScriptMode_FW", 1 },
2597     {20, "SleepTask", "SleepTask_FW", 1 },
2598     {20, "strcmp", "j_strcmp_FW", 0 },
2599     {20, "strcmp", "strcmp_FW", 0 },
2600     {20, "strcpy", "strcpy_FW", 1 },
2601     {20, "strlen", "strlen_FW", 1 },
2602     {20, "StartRecModeMenu", "StartRecModeMenu_FW", 1 },
2603     {20, "TakeSemaphore", "TakeSemaphore_FW", 1 },
2604     {20, "UIFS_WriteFirmInfoToFile", "UIFS_WriteFirmInfoToFile_FW", 1 },
2605     {20, "UnlockMainPower", "UnlockMainPower_FW", 1 },
2606     {20, "VbattGet", "VbattGet_FW", 1 },
2607     //{20, "write", "Write_FW", 1 },
2608     {20, "Write", "Write_FW", 1 },
2609     {20, "task_CaptSeq", "task_CaptSeqTask", 1 },
2610     {20, "task_ExpDrv", "task_ExpDrvTask", 1 },
2611     {20, "task_FileWrite", "task_FileWriteTask", 1 },
2612     {20, "task_RotaryEncoder", "task_JogDial", 1 },
2613     {20, "task_RotaryEncoder", "task_RotarySw", 1 },
2614     {20, "TurnOnDisplay", "DispCon_TurnOnDisplay_FW", 0 },
2615     {20, "TurnOffDisplay", "DispCon_TurnOffDisplay_FW", 0 },
2616     {20, "DoAELock", "PT_DoAELock_FW", 0x01000002 },
2617     {20, "DoAELock", "SS.DoAELock_FW", 0x01000002 },
2618     {20, "DoAFLock", "PT_DoAFLock_FW", 0x01000002 },
2619     {20, "DoAFLock", "SS.DoAFLock_FW", 0x01000002 },
2620     {20, "UnlockAE", "PT_UnlockAE_FW", 0x01000002 },
2621     {20, "UnlockAE", "SS.UnlockAE_FW", 0x01000002 },
2622     {20, "UnlockAF", "PT_UnlockAF_FW", 0x01000002 },
2623     {20, "UnlockAF", "SS.UnlockAF_FW", 0x01000002 },
2624     {20, "MFOn", "MFOn_FW", 1 },
2625     {20, "MFOff", "MFOff_FW", 1 },
2626     {20, "PT_MFOn", "PT_MFOn_FW", 1 },
2627     {20, "PT_MFOff", "PT_MFOff_FW", 1 },
2628     {20, "SS_MFOn", "SS.MFOn_FW", 1 },
2629     {20, "SS_MFOff", "SS.MFOff_FW", 1 },
2630     {20, "SetLogicalEventActive", "UiEvnt_SetLogicalEventActive_FW", 1 },
2631     {20, "GetAdChValue", "GetAdChValue_FW", 0 },
2632     {20, "CalcLog10", "CalcLog10_FW", 4 },
2633     {20, "HwOcReadICAPCounter", "GetCurrentMachineTime", 1 },
2634     {20, "DisableISDriveError", "DisableISDriveError_FW", 1},
2635     {20, "SetImageMode", "SetImageMode_FW", 0x01000002 },
2636     {20, "GetVideoOutType", "GetVideoOutType_FW", 1},
2637     {20, "GetCurrentDriveBaseSvValue", "GetCurrentDriveBaseSvValue_FW", 0x01000002 },
2638 
2639     { 1, "ExportToEventProcedure_FW", "ExportToEventProcedure", 1 },
2640     { 1, "AllocateMemory", "AllocateMemory", 1 },
2641     { 1, "Close", "Close", 1 },
2642     { 1, "CreateTask", "CreateTask", 1 },
2643     //{ 1, "DoAFLock", "PT_DoAFLock", 0x01000002 },
2644     { 1, "ExitTask", "ExitTask", 1 },
2645     { 1, "exmem_alloc", "ExMem.AllocCacheable", 4 },
2646     { 1, "exmem_free", "ExMem.FreeCacheable", 0x01000003 },
2647     { 1, "exmem_ualloc", "ExMem.AllocUncacheable", 4 },
2648     { 1, "exmem_ufree", "ExMem.FreeUncacheable", 0x01000003 },
2649     { 1, "Fclose_Fut", "Fclose_Fut", 1 },
2650     { 1, "Feof_Fut", "Feof_Fut", 1 },
2651     { 1, "Fflush_Fut", "Fflush_Fut", 1 },
2652     { 1, "Fgets_Fut", "Fgets_Fut", 1 },
2653     { 1, "Fopen_Fut", "Fopen_Fut", 1 },
2654     { 1, "Fread_Fut", "Fread_Fut", 1 },
2655     { 1, "FreeMemory", "FreeMemory", 1 },
2656     { 1, "Fseek_Fut", "Fseek_Fut", 1 },
2657     { 1, "Fwrite_Fut", "Fwrite_Fut", 1 },
2658     { 1, "GetParameterData", "PTM_RestoreUIProperty", 0xF0000004 },
2659     { 1, "GetPropertyCase", "PT_GetPropertyCaseString", 1 },
2660     { 1, "GetPropertyCase", "PT_GetPropertyCaseInt", 0x0100000F },
2661     { 1, "GetPropertyCase", "GetPropertyCase", 0x0100000F },
2662     { 1, "GetSDProtect", "GetSDProtect", 1 },
2663     { 1, "GetSystemTime", "GetSystemTime", 1 },
2664     { 1, "LEDDrive", "LEDDrive", 1 },
2665     { 1, "LockMainPower", "LockMainPower", 1 },
2666     { 1, "Lseek", "Lseek", 1 },
2667     { 1, "lseek", "Lseek", 1 },
2668     { 1, "memcpy", "memcpy", 1 },
2669     { 1, "memcmp", "memcmp", 1 },
2670     { 1, "memset", "memset", 1 },
2671     { 1, "NewTaskShell", "NewTaskShell", 1 },
2672     { 1, "Open", "Open", 1 },
2673     { 1, "PostLogicalEventToUI", "PostLogicalEventToUI", 1 },
2674     { 1, "PostLogicalEventForNotPowerType", "PostLogicalEventForNotPowerType", 1 },
2675     //{ 1, "Read", "Read", 1 },
2676     //{ 1, "read", "Read", 1 },
2677     { 1, "RefreshPhysicalScreen", "RefreshPhysicalScreen", 1 },
2678     { 1, "SetAutoShutdownTime", "SetAutoShutdownTime", 1 },
2679     { 1, "SetCurrentCaptureModeType", "SetCurrentCaptureModeType", 1 },
2680     { 1, "SetLogicalEventActive", "UiEvnt_SetLogicalEventActive", 1 },
2681     { 1, "SetParameterData", "PTM_BackupUIProperty", 1 },
2682     { 1, "SetPropertyCase", "PT_SetPropertyCaseInt", 0x01000003 },
2683     { 1, "SetPropertyCase", "SetPropertyCase", 0x01000004 },
2684     { 1, "SetScriptMode", "SetScriptMode", 1 },
2685     { 1, "SleepTask", "SleepTask", 1 },
2686     { 1, "strcmp", "strcmp", 0 },
2687     { 1, "strcpy", "strcpy", 1 },
2688     { 1, "strlen", "strlen", 1 },
2689     { 1, "strtol", "atol", 3 },
2690     { 1, "TakeSemaphore", "TakeSemaphore", 1 },
2691     { 1, "UIFS_WriteFirmInfoToFile", "UIFS_WriteFirmInfoToFile", 1 },
2692     //{ 1, "UnlockAF", "PT_UnlockAF", 0x01000002 },
2693     { 1, "UnlockMainPower", "UnlockMainPower", 1 },
2694     { 1, "VbattGet", "VbattGet", 1 },
2695     //{ 1, "Write", "Write", 1 },
2696     //{ 1, "write", "Write", 1 },
2697     { 1, "GUISrv_StartGUISystem", "GUISrv_StartGUISystem", 1 },
2698 
2699     { 2, "GetBatteryTemperature", "GetBatteryTemperature", 1 },
2700     { 2, "GetCCDTemperature", "GetCCDTemperature", 1 },
2701     { 2, "GetOpticalTemperature", "GetOpticalTemperature", 1 },
2702     { 2, "GetFocusLensSubjectDistance", "GetCurrentTargetDistance", 1 },
2703     { 2, "GetZoomLensCurrentPoint", "GetZoomLensCurrentPoint", 1 },
2704     { 2, "GetZoomLensCurrentPosition", "GetZoomLensCurrentPosition", 1 },
2705     { 2, "MoveFocusLensToDistance", "MoveFocusLensToDistance", 1 },
2706     { 2, "MoveZoomLensWithPoint", "MoveZoomLensWithPoint", 1 },
2707     { 2, "GetCurrentAvValue", "GetCurrentAvValue", 1 },
2708     { 2, "PT_MoveOpticalZoomAt", "PT_MoveOpticalZoomAt", 1 },
2709     { 2, "PT_MoveOpticalZoomAt", "SS.MoveOpticalZoomAt", 1 },
2710     { 2, "PT_MoveDigitalZoomToWide", "PT_MoveDigitalZoomToWide", 1 },
2711     { 2, "PT_MoveDigitalZoomToWide", "SS.MoveDigitalZoomToWide", 1 },
2712     { 2, "MoveIrisWithAv", "MoveIrisWithAv", 1},
2713     { 2, "PutInNdFilter", "TurnOnNdFilter", 1 },
2714     { 2, "PutOutNdFilter", "TurnOffNdFilter", 1 },
2715     { 2, "PutInNdFilter", "PutInNdFilter", 1 },
2716     { 2, "PutOutNdFilter", "PutOutNdFilter", 1 },
2717     { 2, "IsStrobeChargeCompleted", "EF.IsChargeFull", 1 },
2718     { 2, "GetPropertyCase", "PT_GetPropertyCaseInt", 0x01000012 },
2719     { 2, "SetPropertyCase", "PT_SetPropertyCaseInt", 0x01000008 },
2720     { 2, "SetPropertyCase", "PT_SetPropertyCaseInt", 0x01000009 },
2721     //{ 2, "UnlockAF", "PT_UnlockAF", 0x01000002 },
2722     //{ 2, "UnlockAF", "SS.UnlockAF", 0x01000002 },
2723     //{ 2, "DoAFLock", "PT_DoAFLock", 0x01000002 },
2724     //{ 2, "DoAFLock", "SS.DoAFLock", 0x01000002 },
2725     { 2, "GetSystemTime", "PT_GetSystemTime", 0x01000003 },
2726     { 2, "PT_PlaySound", "PT_PlaySound", 0x01000005 },
2727     { 2, "StartRecModeMenu", "StartRecModeMenu", 1 },
2728     { 2, "GetSDProtect", "GetSDProtect", 1 },
2729     { 2, "DispCon_ShowBitmapColorBar", "DispCon_ShowBitmapColorBar", 1 },
2730     { 2, "SetAE_ShutterSpeed", "SetAE_ShutterSpeed", 1 },
2731     { 2, "ResetZoomLens", "ResetZoomLens", 1 },
2732     { 2, "ResetFocusLens", "ResetFocusLens", 1 },
2733     { 2, "NR_GetDarkSubType", "NR_GetDarkSubType", 1 },
2734     { 2, "NR_GetDarkSubType", "NRTBL.GetDarkSubType", 1 },
2735     { 2, "NR_SetDarkSubType", "NR_SetDarkSubType", 1 },
2736     { 2, "NR_SetDarkSubType", "NRTBL.SetDarkSubType", 1 },
2737     { 2, "SavePaletteData", "SavePaletteData", 1 },
2738     { 2, "GetVRAMHPixelsSize", "GetVRAMHPixelsSize", 1 },
2739     { 2, "GetVRAMVPixelsSize", "GetVRAMVPixelsSize", 1 },
2740     { 2, "EngDrvIn", "EngDrvIn", 2 },
2741     { 2, "EngDrvOut", "EngDrvOut", 0x01000005 },
2742     { 2, "EngDrvRead", "EngDrvRead", 2 },
2743     { 2, "EngDrvBits", "EngDrvBits", 0x01000007 },
2744     { 2, "EngDrvBits", "EngDrvBits", 0x01000005 },
2745     { 2, "exmem_alloc", "ExMem.AllocCacheable", 4 },
2746     { 2, "exmem_free", "ExMem.FreeCacheable", 0x01000003 },
2747     { 2, "exmem_ualloc", "ExMem.AllocUncacheable", 4 },
2748     { 2, "exmem_ufree", "ExMem.FreeUncacheable", 0x01000003 },
2749 
2750     { 2, "PTM_GetCurrentItem", "PTM_GetCurrentItem", 2 }, // s5is
2751     { 2, "PTM_SetCurrentItem", "PTM_SetCurrentItem", 4 }, // s5is
2752     { 2, "PTM_NextItem", "PTM_NextItem", 2 }, // s5is
2753     { 2, "PTM_PrevItem", "PTM_PrevItem", 2 }, // s5is
2754     { 2, "PTM_SetPropertyEnable", "PTM_SetProprietyEnable", 4 }, // s5is
2755 
2756     { 3, "AllocateMemory", "AllocateMemory", 1 },
2757     { 3, "FreeMemory", "FreeMemory", 1 },
2758     { 3, "PostLogicalEventToUI", "PostLogicalEventToUI", 1 },
2759     { 3, "PostLogicalEventForNotPowerType", "PostLogicalEventForNotPowerType", 1 },
2760     { 3, "LockMainPower", "LockMainPower", 1 },
2761     { 3, "UnlockMainPower", "UnlockMainPower", 1 },
2762     { 3, "SetAutoShutdownTime", "SetAutoShutdownTime", 1 },
2763     { 3, "NewTaskShell", "NewTaskShell", 1 },
2764     { 3, "VbattGet", "VbattGet", 1 },
2765     { 3, "LEDDrive", "LEDDrive", 1 },
2766     { 3, "SetPropertyCase", "PT_SetPropertyCaseInt", 0x01000003 },
2767     //{ 3, "UnlockAF", "PT_UnlockAF", 0x01000002 },
2768     //{ 3, "DoAFLock", "PT_DoAFLock", 0x01000002 },
2769     { 3, "UIFS_WriteFirmInfoToFile", "UIFS_WriteFirmInfoToFile", 1 },
2770     { 3, "PT_MoveOpticalZoomAt", "PT_MoveOpticalZoomAt", 1 },
2771     { 3, "PT_MoveDigitalZoomToWide", "PT_MoveDigitalZoomToWide", 1 },
2772     { 3, "PT_PlaySound", "PT_PlaySound", 1 },
2773     { 3, "exmem_alloc", "ExMem.AllocCacheable", 4 },
2774     { 3, "exmem_free", "ExMem.FreeCacheable", 0x01000003 },
2775     { 3, "exmem_ualloc", "ExMem.AllocUncacheable", 4 },
2776     { 3, "exmem_ufree", "ExMem.FreeUncacheable", 0x01000003 },
2777     { 3, "GetSDProtect", "GetSDProtect", 1 },
2778 
2779     { 4, "TurnOnBackLight", "TurnOnBackLight", 1 },
2780     { 4, "TurnOffBackLight", "TurnOffBackLight", 1 },
2781     { 4, "EnterToCompensationEVF", "SSAPI::EnterToCompensationEVF", 1 },
2782     { 4, "EnterToCompensationEVF", "ExpComp On", 1 },
2783     { 4, "EnterToCompensationEVF", "ExpOn", 1 },
2784     { 4, "ExitFromCompensationEVF", "SSAPI::ExitFromCompensationEVF", 1 },
2785     { 4, "ExitFromCompensationEVF", "ExpComp Off", 1 },
2786     { 4, "ExitFromCompensationEVF", "ExpOff", 1 },
2787     { 4, "PB2Rec", "AC:PB2Rec", 1 },
2788     { 4, "PB2Rec", "AC:PB2Rec", 6 },
2789     { 4, "PB2Rec", "AC:PB2Rec", 9 },
2790     { 4, "PB2Rec", "AC:PB2Rec", 11 },
2791     { 4, "Rec2PB", "AC:Rec2PB", 1 },
2792     { 4, "Rec2PB", "AC:Rec2PB", 2 },
2793     { 4, "RefreshPhysicalScreen", "ScreenUnLock", 1 },
2794     { 4, "RefreshPhysicalScreen", "ScreenUnLock", 7 },
2795     { 4, "RefreshPhysicalScreen", "ScreenUnLock", 15 },
2796     { 4, "RefreshPhysicalScreen", "Reduce ScreenUnLock", 5 },
2797     { 4, "RefreshPhysicalScreen", "Window:IneffectiveLockPhysicalScreen", 8 },
2798     { 4, "UnsetZoomForMovie", "ZoomCon_UnsetZoomForMovie", 1 },
2799     { 4, "ExpCtrlTool_StopContiAE", "StopContiAE", 9 },
2800     { 4, "ExpCtrlTool_StopContiAE", "StopContiAE", 10 },
2801     { 4, "ExpCtrlTool_StopContiAE", "StopContiAE", 11 },
2802     { 4, "ExpCtrlTool_StartContiAE", "StartContiAE", 9 },
2803     { 4, "ExpCtrlTool_StartContiAE", "StartContiAE", 10 },
2804     { 4, "ExpCtrlTool_StartContiAE", "StartContiAE", 11 },
2805     { 4, "ExecuteEventProcedure", "Can not Execute ", 14 },
2806 
2807     { 5, "UIFS_WriteFirmInfoToFile", "UIFS_WriteFirmInfoToFile", 1 },
2808     { 5, "CreateTask", "CreateTask", 1 },
2809     { 5, "hook_CreateTask", "CreateTask", 1 },
2810     { 5, "ExitTask", "ExitTask", 1 },
2811     { 5, "SleepTask", "SleepTask", 1 },
2812     { 5, "DeleteSemaphore", "DeleteSemaphore", 1 },
2813     { 5, "CreateCountingSemaphore", "CreateCountingSemaphore", 1 },
2814     //                                                                   R20   R23   R31   R39   R43   R45   R47   R49   R50   R51   R52   R54   R55   R57   R58   R59
2815     { 5, "UpdateMBROnFlash", "MakeBootDisk", 0x01000003,                  11,   11,   11,   11,   11,   11,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1 },
2816     { 5, "MakeSDCardBootable", "MakeBootDisk", 0x01000003,                 1,    1,    1,    1,    1,    1,    8,    8,    8,    8,    8,    9,    9,    9,    9,    9 },
2817 
2818     { 5, "PTM_GetCurrentItem", "PTM_GetCurrentItem", 1 },
2819     { 5, "PTM_SetCurrentItem", "PTM_SetCurrentItem", 1 },
2820     { 5, "PTM_NextItem", "PTM_NextItem", 1 },
2821     { 5, "PTM_PrevItem", "PTM_PrevItem", 1 },
2822     { 5, "PTM_SetPropertyEnable", "PTM_SetProprietyEnable", 1 },
2823 
2824     //{ 6, "Restart", "Bye", 0 },
2825     { 6, "reboot_fw_update", "FirmUpgrade.c", 0 },
2826 
2827     { 7, "CreateTaskStrictly", "PhySw", 0x01000001 },
2828     { 7, "CreateTaskStrictly_alt", "FsIoNotifyTask", 0x01000001 },
2829     { 7, "RegisterInterruptHandler", "WdtInt", 0x01000001 },
2830     { 7, "LogCameraEvent", "BufAccBeep", 0x01000001 },
2831     { 7, "LogCameraEvent", "MyCamFunc_PlaySound_MYCAM_COVER_OPEN", 0x01000001 },
2832     { 7, "DebugAssert", "Console.c", 0x01000001 },
2833     { 7, "exmem_assert", "Type < MAX_NUM_OF_EXMEMORY_TYPE", 0x01000001 },
2834 
2835     { 8, "WriteSDCard", "Mounter.c", 0 },
2836 
2837     // Ensure ordering in func_names is correct for dependencies here
2838     //                                                                   R20   R23   R31   R39   R43   R45   R47   R49   R50   R51   R52   R54   R55   R57   R58   R59
2839     { 9, "kbd_p1_f", "task_PhySw", 0,                                      5,    5,    5,    5,    5,    5,    5,    5,    5,    5,    5,    5,    5,    5,    5,    5 },
2840     { 9, "kbd_p2_f", "task_PhySw", 0,                                      7,    7,    7,    7,    7,    7,    7,    7,    7,    7,    7,    7,    7,    7,    7,    7 },
2841     { 9, "kbd_read_keys", "kbd_p1_f", 0,                                   2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2 },
2842     { 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 },
2843     { 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 },
2844     { 9, "GetKbdState", "kbd_read_keys", 0,                                8,    8,    8,    8,    8,    8,    8,    8,    8,    8,    8,    8,    8,    8,    8,    8 },
2845     { 9, "GetKbdState", "kbd_read_keys", 0,                                9,    9,    9,    9,    9,    9,    9,    9,    9,    9,    9,    9,    9,    9,    9,    9 },
2846     { 9, "strtolx", "strtol", 0,                                           1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1 },
2847     { 9, "mkdir", "MakeDirectory_Fut", 0x01000001,                        17,   17,   17,   17,   17,   17,   17,   17,   17,   17,   17,   17,   17,   17,   17,   17 },
2848     { 9, "mkdir", "MakeDirectory_Fut", 0x01000002,                        17,   17,   17,   17,   17,   17,   17,   17,   17,   17,   17,   17,   17,   17,   17,   17 },
2849     { 9, "time", "MakeDirectory_Fut", 0,                                  12,   12,   12,   12,   12,   12,   12,   12,   12,   12,   12,   12,   12,   12,   12,   12 },
2850     { 9, "stat", "_uartr_req", 0,                                          0,    0,    0,    4,    4,    4,    4,    4,    4,    4,    4,    4,    4,    4,    4,    4 },
2851     { 9, "PostMessageQueue", "PostMessageQueueStrictly", 0,                3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3 },
2852     { 9, "WaitForAnyEventFlag", "WaitForAnyEventFlagStrictly", 0,          3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3 },
2853     { 9, "WaitForAllEventFlag", "WaitForAllEventFlagStrictly", 0,          3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3 },
2854     { 9, "CreateMessageQueue", "CreateMessageQueueStrictly", 0,            1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1 },
2855     { 9, "CreateRecursiveLock", "CreateRecursiveLockStrictly", 0,          1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1 },
2856     { 9, "CreateEventFlag", "CreateEventFlagStrictly", 0,                  1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1 },
2857     { 9, "_GetSystemTime", "GetSystemTime", 0,                             2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2 },
2858     { 9, "close", "Close", 0,                                              2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2,    2 },
2859     { 9, "open", "Open", 0,                                                3,    3,    3,    3,   16,   16,   35,   35,   35,   35,   35,   35,   35,   35,   35,   35 },
2860     { 9, "open", "Open", 0,                                                3,    3,    3,   13,   16,   16,   35,   35,   35,   35,   35,   35,   35,   35,   35,   35 },
2861     { 9, "_divmod_signed_int", "PT_mod_FW", 0,                             4,    7,    7,    7,    7,    7,    6,    6,    6,    6,    6,    6,    6,    6,    6,    6 },
2862     { 9, "_divmod_signed_int", "PT_mod_FW", 0,                             0,    4,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0 },
2863     { 9, "_divmod_signed_int", "mod_FW", 0,                                0,    0,    0,    0,    0,    0,    0,    0,    0,    4,    4,    4,    4,    4,    4,    4 },
2864     { 9, "_divmod_unsigned_int", "SetTimerAfter", 0,                      23,   23,   23,   23,   23,   23,   23,   23,   23,   23,   23,    0,    0,    0,    0,    0 },
2865     { 9, "_divmod_unsigned_int", "DispCon_ShowWhiteChart_FW", 0,           0,    0,    0,    0,    0,    0,    0,    0,    0,    0,   15,   15,   15,   15,   13,   13 },
2866     { 9, "_divmod_unsigned_int", "DispCon_ShowWhiteChart_FW", 0,           0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    8,    8,    8,    0,    0,    0 },
2867     { 9, "_dflt", "CalcLog10", 0,                                          9,    9,    9,    9,    9,    9,    9,    9,    9,    9,    9,    9,    9,    9,    9,    9 },
2868     { 9, "_dfltu", "CalcLog10", 0,                                         4,    4,    4,    4,    4,    4,    4,    4,    4,    4,    4,    4,    4,    4,    4,    4 },
2869     { 9, "_dmul", "CalcLog10", 0,                                         12,   12,   12,   12,   12,   12,   12,   12,   12,   12,   12,   12,   12,   12,   12,   12 },
2870     { 9, "_dfix", "CalcLog10", 0,                                         14,   14,   14,   14,   14,   14,   14,   14,   14,   14,   14,   14,   14,   14,   14,   14 },
2871     { 9, "_dadd", "_pow", 0,                                              26,   26,   26,   26,   26,   26,   29,   29,   29,   29,   29,   29,   29,   29,   29,   29 },
2872     { 9, "_dadd", "_pow", 0,                                               1,    1,    1,    1,    1,    1,   24,   24,    1,    1,    1,    1,    1,    1,    1,    1 }, // s100, sx230 (100c only...)
2873     { 9, "_scalbn", "_log", 0,                                            19,   19,   19,   19,   19,   19,   18,   18,   18,   18,   18,   18,   18,   18,   18,   18 },
2874     { 9, "_scalbn", "_log", 0,                                             1,    1,    1,    1,    1,    1,   14,   14,    1,    1,    1,    1,    1,    1,    1,    1 }, // s100, sx230 (100c only...)
2875     { 9, "_safe_sqrt", "CalcSqrt_FW", 0,                                   0,    0,   -3,   -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6,   -6 },
2876     { 9, "_ddiv", "ConvertApexStdToApex_FW", 0,                            0,    0,    0,   21,   21,   21,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0 },
2877     { 9, "_fflt", "ConvertApexStdToApex_FW", 0,                           -7,   -7,   -7,   -7,   -7,   -7,   -7,   -7,   -7,   -7,   -7,   -7,   -7,   -7,   -7,   -7 },
2878     { 9, "_ffix", "ConvertApexStdToApex_FW", 0,                           -4,   -4,   -4,   -4,   -4,   -4,   -4,   -4,   -4,   -4,   -4,   -4,   -4,   -4,   -4,   -4 },
2879     { 9, "_fmul", "ConvertApexStdToApex_FW", 0,                           -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5,   -5 },
2880     { 9, "_fdiv", "ConvertApexToApexStd_FW", 0,                           -3,   -3,   -3,   -3,   -3,   -3,   -3,   -3,   -3,   -3,   -3,   -3,   -3,   -3,   -3,   -3 },
2881     { 9, "GetSRAndDisableInterrupt", "_GetSystemTime", 0,                  9,    9,    9,    9,    9,    9,    9,    9,    9,    9,    9,    9,    9,    9,    9,    9 },
2882     { 9, "SetSR", "_GetSystemTime", 0,                                    12,   12,   12,   12,   12,   12,   12,   12,   12,   12,   12,   12,   12,   12,   12,   12 },
2883     { 9, "MoveOpticalZoomAt", "PT_MoveOpticalZoomAt_FW", 0,                1,    2,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3 },
2884     { 9, "MoveOpticalZoomAt", "PT_MoveOpticalZoomAt_FW", 0,                1,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3 },
2885     { 9, "MoveOpticalZoomAt", "SS.MoveOpticalZoomAt_FW", 0,                0,    0,    0,    0,    0,    0,    0,    0,    0,    3,    5,    5,    5,    5,    5,    5 },
2886     { 9, "SetVideoOutType", "SetVideoOutType_FW", 0,                       1,    1,    1,    1,    1,    1,    1,    1,    1,    2,    2,    2,    2,    2,    2,    2 },
2887     { 9, "cache_flush_range", "AllocateUncacheableMemory", 0,              0,    0,   12,   12,   12,   12,   12,   12,   12,   12,   12,    0,    0,    0,    0,    0 },
2888     { 9, "cache_clean_range", "AllocateUncacheableMemory", 0,              9,    9,    9,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0 },
2889     { 9, "dcache_flush_range", "AllocateUncacheableMemory", 0,             0,    0,    0,    0,    0,    0,    0,    0,    0,    0,   11,   11,   11,   11,   11,   11 },
2890     { 9, "bzero", "exec_FW", 0,                                            6,    6,    6,    6,    6,    6,    6,    6,    6,    6,    6,    6,    6,    6,    6,    6 },
2891 
2892     //                                                                   R20   R23   R31   R39   R43   R45   R47   R49   R50   R51   R52   R54   R55   R57   R58   R59
2893 //    { 11, "DebugAssert", "\nAssert: File %s Line %d\n", 0,                 5,    5,    5,    5,    5,    5,    5,    5,    5,    5,    1,    6 },
2894     { 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 },
2895     { 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 },
2896     { 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 },
2897     { 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 },
2898     { 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 },
2899     { 11, "_log", (char*)log_test, 0x01000001,                             1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1 },
2900     { 11, "_uartr_req", "A/uartr.req", 0,                                  3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,    3 },
2901     { 11, "MenuIn", "MenuIn", 0,                                           1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1 },
2902     { 11, "MenuOut", "MenuOut", 0,                                         1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1 },
2903     { 11, "MenuIn", "SSAPI::MenuIn", 0,                                    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1 },
2904     { 11, "MenuOut", "SSAPI::MenuOut", 0,                                  1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1,    1 },
2905 
2906     //                                                                   R20   R23   R31   R39   R43   R45   R47   R49   R50   R51   R52   R54   R55   R57   R58   R59
2907     { 12, "DeleteFile_Fut", "DeleteFile_Fut", 1,                        0x38, 0x38, 0x4C, 0x4C, 0x4C, 0x54, 0x54, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
2908     { 12, "AllocateUncacheableMemory", "AllocateUncacheableMemory", 1,  0x2C, 0x2C, 0x2C, 0x2C, 0x2C, 0x34, 0x34, 0x34, 0x4C, 0x4C, 0x4C, 0x4C, 0x54, 0x54, 0x54, 0x54 },
2909     { 12, "FreeUncacheableMemory", "FreeUncacheableMemory", 1,          0x30, 0x30, 0x30, 0x30, 0x30, 0x38, 0x38, 0x38, 0x50, 0x50, 0x50, 0x50, 0x58, 0x58, 0x58, 0x58 },
2910     { 12, "free", "free", 1,                                            0x28, 0x28, 0x28, 0x28, 0x28, 0x30, 0x30, 0x30, 0x48, 0x48, 0x48, 0x48, 0x50, 0x50, 0x50, 0x50 },
2911     { 12, "malloc", "malloc", 0x01000003,                               0x24, 0x24, 0x24, 0x24, 0x24, 0x2C, 0x2C, 0x2C, 0x44, 0x44, 0x44, 0x44, 0x4c, 0x4c, 0x4c, 0x4c }, // uses 'malloc_strictly'
2912     { 12, "TakeSemaphore", "TakeSemaphore", 1,                          0x14, 0x14, 0x14, 0x14, 0x14, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C },
2913     { 12, "GiveSemaphore", "GiveSemaphore", 1,                          0x18, 0x18, 0x18, 0x18, 0x18, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 },
2914     { 12, "_log10", "_log10", 0x01000006,                              0x278,0x280,0x280,0x284,0x294,0x2FC,0x2FC,0x31C,0x354,0x35C,0x35C,0x35C,0x388,0x38c,0x390,0x394 }, // uses 'CalcLog10'
2915     { 12, "_log10", "_log10", 0x01000006,                              0x000,0x278,0x27C,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x38c,0x000,0x000,0x000 },
2916     { 12, "_log10", "_log10", 0x01000006,                              0x000,0x000,0x2C4,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000 },
2917     { 12, "ClearEventFlag", "ClearEventFlag", 1,                        0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04 },
2918     { 12, "SetEventFlag", "SetEventFlag", 1,                            0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08 },
2919     { 12, "WaitForAnyEventFlag", "WaitForAnyEventFlag", 1,              0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c },
2920     { 12, "WaitForAllEventFlag", "WaitForAllEventFlag", 1,              0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10 },
2921 
2922     { 13, "strftime", "Sunday", 1 },
2923 
2924     { 15, "LocalTime", "%04d:%02d:%02d %02d:%02d:%02d", 0x01000001 },
2925     { 15, "GetMemInfo", "Malloc Information\n", 0x01000001 },
2926     { 15, "GetMemInfo", "Malloc Information (%s type)\n", 0x01000001 },
2927     { 15, "vsprintf", "\nCPrintf Size Over!!", 0x01000001 },
2928     { 15, "ReadFastDir", "ReadFast_ERROR\n", 0x01000001 },
2929     { 15, "OpenFastDir", "OpenFastDir_ERROR\n", 0x01000001 },
2930     { 15, "realloc", "fatal error - scanner input buffer overflow", 0x01000001 },
2931     { 15, "CreateBinarySemaphore", "SdPower.c", 0x01000001 },
2932     { 15, "get_resource_pointer", "Not found icon resource.\r\n", 0x01000001 },
2933     { 15, "get_self_task_id", "ASSERT!! %s Line %d\n", 0x01000001 },
2934     { 15, "get_current_exp", "Exp  Av %d, Tv %d, Gain %d\r", 0x01000001 },
2935     { 15, "EnableDispatch_low", "\n%s Task was Suspended.\n", 0x01000001 },
2936     //{ 15, "DoMovieFrameCapture", "DoMovieFrameCapture executed.",  0x01000001 },
2937     //                                                                           R20     R23     R31     R39     R43     R45     R47     R49     R50     R51     R52     R54     R55     R57     R58     R59
2938     { 15, "SetHPTimerAfterTimeout", "FrameRateGenerator.c", 0x01000001,          0x0007, 0x0007, 0x0007, 0x0007, 0x0007, 0x0007, 0x0007, 0x0007, 0x0007, 0x0007, 0x0001, 0x0007, 0x0007, 0x0007, 0x0007, 0x0007 },
2939     { 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!
2940 
2941     { 16, "DeleteDirectory_Fut", (char*)DeleteDirectory_Fut_test, 0x01000001 },
2942     { 16, "MakeDirectory_Fut", (char*)MakeDirectory_Fut_test, 0x01000001 },
2943     { 16, "RenameFile_Fut", (char*)RenameFile_Fut_test, 0x01000001 },
2944 
2945     { 17, "ScreenLock", "StartRecModeMenu", 0 },
2946     { 17, "ScreenUnlock", "StartRecModeMenu", 0 },
2947 
2948     // Ensure ordering in func_names is correct for dependencies here
2949     //                                                                           R20     R23     R31     R39     R43     R45     R47     R49     R50     R51     R52     R54     R55     R57     R58     R59
2950     { 19, "GetSemaphoreValue", "GiveSemaphore", 0,                               0x000e, 0x000e, 0x000e, 0x000e, 0x000e, 0x000e, 0x000e, 0x000e, 0x000e, 0x000e, 0x000e, 0x0014, 0x0014, 0x0014, 0x0014, 0x0014 },
2951     { 19, "GetSemaphoreValue", "GiveSemaphore", 0,                               0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0x000f, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000 },
2952     { 19, "CreateMessageQueueStrictly", "CreateTaskStrictly", 0,                 0x000d, 0x000d, 0x000d, 0x000d, 0x000d, 0x000d, 0x000d, 0x000d, 0x000d, 0x000d, 0x000d, 0x000d, 0x000d, 0x000d, 0x000d, 0x000d },
2953     { 19, "CreateMessageQueueStrictly", "CreateTaskStrictly", 0,                 0x000d, 0x000d, 0x000d, 0x000d, 0x000d, 0x000d, 0x000d, 0x000d, 0x000d, 0x000d, 0x000e, 0x000e, 0x000e, 0x000e, 0x000e, 0x000e },
2954     { 19, "CreateEventFlagStrictly", "CreateMessageQueueStrictly", 0,            0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009 },
2955     { 19, "CreateEventFlagStrictly", "CreateMessageQueueStrictly", 0,            0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x000a, 0x000a, 0x000a, 0x000a, 0x000a, 0x000a },
2956     { 19, "CreateBinarySemaphoreStrictly", "CreateEventFlagStrictly", 0,         0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009 },
2957     { 19, "CreateBinarySemaphoreStrictly", "CreateEventFlagStrictly", 0,         0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x000a, 0x000a, 0x000a, 0x000a, 0x000a, 0x000a },
2958     { 19, "CreateCountingSemaphoreStrictly", "CreateBinarySemaphoreStrictly", 0, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009 },
2959     { 19, "CreateCountingSemaphoreStrictly", "CreateBinarySemaphoreStrictly", 0, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x000a, 0x000a, 0x000a, 0x000a, 0x000a, 0x000a },
2960     { 19, "CreateRecursiveLockStrictly", "CreateCountingSemaphoreStrictly", 0,   0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009 },
2961     { 19, "CreateRecursiveLockStrictly", "CreateCountingSemaphoreStrictly", 0,   0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x000a, 0x000a, 0x000a, 0x000a, 0x000a, 0x000a },
2962     { 19, "TakeSemaphoreStrictly", "CreateRecursiveLockStrictly", 0,             0x0001, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0xf000, 0xf000 }, // name made up
2963     { 19, "TakeSemaphoreStrictly", "CreateRecursiveLockStrictly", 0,             0x0001, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x000a, 0x000a, 0x000a, 0x000a, 0x0014, 0x0014 }, // name made up
2964     { 19, "ReceiveMessageQueueStrictly", "TakeSemaphoreStrictly", 0,             0x000b, 0x000b, 0x000b, 0x000b, 0x000b, 0x000b, 0x000b, 0x000b, 0x000b, 0x000b, 0x000b, 0x000b, 0x000b, 0x000b, 0x000b, 0x000b }, // name made up
2965     { 19, "PostMessageQueueStrictly", "ReceiveMessageQueueStrictly", 0,          0x000b, 0x000b, 0x000b, 0x000b, 0x000b, 0x000b, 0x000b, 0x000b, 0x000b, 0x000b, 0x000b, 0x000b, 0x000b, 0x000b, 0x000b, 0x000b }, // name made up
2966     { 19, "WaitForAnyEventFlagStrictly", "PostMessageQueueStrictly", 0,          0x000b, 0x000b, 0x000b, 0x000b, 0x000b, 0x000b, 0x000b, 0x000b, 0x000b, 0x000b, 0x000b, 0x000b, 0x000b, 0x000b, 0x000b, 0x000b }, // name made up
2967     { 19, "WaitForAllEventFlagStrictly", "WaitForAnyEventFlagStrictly", 0,       0x000b, 0x000b, 0x000b, 0x000b, 0x000b, 0x000b, 0x000b, 0x000b, 0x000b, 0x000b, 0x000b, 0x000b, 0x000b, 0x000b, 0x000b, 0x0510 }, // name made up
2968     { 19, "AcquireRecursiveLockStrictly", "WaitForAllEventFlagStrictly", 0,      0x000b, 0x000b, 0x000b, 0x000b, 0x000b, 0x000b, 0x000b, 0x000b, 0x000b, 0x000b, 0x000b, 0x000b, 0x000b, 0x000b, 0x000b, 0x000b }, // name made up
2969 
2970     { 19, "PostMessageQueue", "TryReceiveMessageQueue", 0,                       0x091f, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001 },
2971     { 19, "DeleteMessageQueue", "CreateMessageQueue", 0,                         0x1021, 0x1021, 0x1021, 0x1021, 0x1021, 0x1021, 0x1021, 0x1021, 0x1021, 0x1021, 0x1021, 0x002c, 0x002c, 0x002c, 0x002c, 0x002c },
2972     { 19, "DeleteMessageQueue", "CreateMessageQueue", 0,                         0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0x0027, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000 },
2973     { 19, "ReceiveMessageQueue", "DeleteMessageQueue", 0,                        0x1024, 0x1024, 0x1024, 0x1024, 0x1024, 0x1024, 0x1024, 0x1024, 0x1024, 0x1024, 0x1024, 0x1029, 0x1029, 0x1029, 0x1028, 0x1028 },
2974     { 19, "ReceiveMessageQueue", "DeleteMessageQueue", 0,                        0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0x1025, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000 },
2975     { 19, "TryReceiveMessageQueue", "ReceiveMessageQueue", 0,                    0x002b, 0x002b, 0x1032, 0x1032, 0x1032, 0x1032, 0x1032, 0x1032, 0x1032, 0x1032, 0x1032, 0x073d, 0x073d, 0x073d, 0x073d, 0x073d },
2976     { 19, "TryReceiveMessageQueue", "ReceiveMessageQueue", 0,                    0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0x183e, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000 },
2977     { 19, "TryPostMessageQueue", "PostMessageQueue", 0,                          0x0027, 0x0027, 0x102e, 0x102e, 0x102e, 0x102e, 0x102e, 0x102e, 0x102e, 0x102e, 0x102e, 0x0031, 0x0031, 0x0031, 0x0031, 0x0031 },
2978     { 19, "TryPostMessageQueue", "PostMessageQueue", 0,                          0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0x1031, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000 },
2979     { 19, "GetNumberOfPostedMessages", "TryPostMessageQueue", 0,                 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0015, 0x0015, 0x0015, 0x0015, 0x0015 },
2980     { 19, "DeleteRecursiveLock", "CreateRecursiveLock", 0,                       0x0014, 0x0014, 0x0014, 0x0014, 0x0014, 0x0014, 0x0014, 0x0014, 0x0014, 0x0014, 0x0014, 0x0016, 0x0016, 0x0016, 0x0016, 0x0016 },
2981     { 19, "DeleteRecursiveLock", "CreateRecursiveLock", 0,                       0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0x0016, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000 },
2982     { 19, "AcquireRecursiveLock", "DeleteRecursiveLock", 0,                      0x0014, 0x0014, 0x0014, 0x0014, 0x0014, 0x0014, 0x0014, 0x0014, 0x0014, 0x0014, 0x0014, 0x001a, 0x001a, 0x001a, 0x001a, 0x001a },
2983     { 19, "AcquireRecursiveLock", "DeleteRecursiveLock", 0,                      0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0x0015, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000 },
2984     { 19, "ReleaseRecursiveLock", "AcquireRecursiveLock", 0,                     0x0041, 0x0041, 0x0048, 0x0048, 0x0048, 0x0048, 0x0048, 0x0048, 0x0048, 0x0048, 0x0048, 0x085a, 0x085a, 0x085a, 0x0658, 0x095b },
2985     { 19, "ReleaseRecursiveLock", "AcquireRecursiveLock", 0,                     0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0x004d, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000 },
2986     { 19, "GetEventFlagValue", "ClearEventFlag", 0,                              0x000e, 0x000e, 0x000e, 0x000e, 0x000e, 0x000e, 0x000e, 0x000e, 0x000e, 0x000e, 0x000e, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013 },
2987     { 19, "DeleteEventFlag", "CreateEventFlag", 0,                               0x0016, 0x0016, 0x0016, 0x0016, 0x0016, 0x0016, 0x0016, 0x0016, 0x0016, 0x0016, 0x0016, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018 },
2988     { 19, "DeleteEventFlag", "CreateEventFlag", 0,                               0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0x0018, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000 },
2989     { 19, "CheckAnyEventFlag", "DeleteEventFlag", 0,                             0x0014, 0x0014, 0x0014, 0x0014, 0x0014, 0x0014, 0x0014, 0x0014, 0x0014, 0x0014, 0x0014, 0x001a, 0x001a, 0x001a, 0x001a, 0x001a },
2990     { 19, "CheckAnyEventFlag", "DeleteEventFlag", 0,                             0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0x0015, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000 },
2991     { 19, "CheckAllEventFlag", "CheckAnyEventFlag", 0,                           0x0012, 0x0012, 0x0012, 0x0012, 0x0012, 0x0012, 0x0012, 0x0012, 0x0012, 0x0012, 0x0012, 0x0017, 0x0017, 0x0017, 0x0017, 0x0017 },
2992     { 19, "TryTakeSemaphore", "DeleteSemaphore", 0,                              0x0016, 0x0016, 0x0016, 0x0016, 0x0016, 0x0016, 0x0016, 0x0016, 0x0016, 0x0016, 0x0016, 0x001d, 0x001d, 0x001d, 0x001d, 0x001d },
2993     { 19, "TryTakeSemaphore", "DeleteSemaphore", 0,                              0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0x0018, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000 },
2994     { 19, "SetTimerAfter", "_GetSystemTime", 0,                                  0x004e, 0x004e, 0x004e, 0x004e, 0x004e, 0x004e, 0x004e, 0x004e, 0x004e, 0x004e, 0x004e, 0x004e, 0x004e, 0x0054, 0x0054, 0x005d },
2995     { 19, "SetTimerWhen", "SetTimerAfter", 0,                                    0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x001b, 0x001b, 0x001b, 0x001b, 0x001b },
2996     { 19, "SetTimerWhen", "SetTimerAfter", 0,                                    0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0x001b, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000 },
2997     { 19, "CancelTimer", "SetTimerWhen", 0,                                      0x0019, 0x0019, 0x0019, 0x0019, 0x0019, 0x0019, 0x0019, 0x0019, 0x0019, 0x0019, 0x0019, 0x0019, 0x0019, 0x0019, 0x0019, 0x0019 },
2998     { 19, "CancelHPTimer", "SetHPTimerAfterTimeout", 0,                          0x0022, 0x0022, 0x0022, 0x0022, 0x0022, 0x0022, 0x0022, 0x0022, 0x0022, 0x0022, 0x0022, 0x0022, 0x0022, 0x0022, 0x0022, 0x0022 },
2999     { 19, "SetHPTimerAfterNow", "SetHPTimerAfterTimeout", 0,                    -0x0020,-0x0020,-0x0020,-0x0020,-0x0020,-0x0020,-0x0020,-0x0020,-0x0020,-0x0020,-0x0020,-0x0020,-0x0020,-0x0020,-0x0020,-0x0020 },
3000     //{ 19, "UnregisterInterruptHandler", "RegisterInterruptHandler", 0,         0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013 }, // unreliable on r52+
3001     //{ 19, "GetSRAndDisableInterrupt", "UnregisterInterruptHandler", 0,         0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x004c, 0x004c, 0x004c, 0x004c, 0x004c }, // unreliable on r52+
3002     //{ 19, "SetSR", "UnregisterInterruptHandler", 0,                            0x1007, 0x1007, 0x1007, 0x1007, 0x1007, 0x1007, 0x1007, 0x1007, 0x1007, 0x1007, 0x1007, 0x104d, 0x104d, 0x104d, 0x104d, 0x104d }, // unreliable on r52+
3003     { 19, "EnableInterrupt", "UnregisterInterruptHandler", 0,                    0x170f, 0x170f, 0x170f, 0x170f, 0x170f, 0x170f, 0x170f, 0x170f, 0x170f, 0x170f, 0x170f, 0x1755, 0x1755, 0x1755, 0x1755, 0x1755 },
3004     { 19, "EnableInterrupt", "SetSR", 0,                                         0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0x1708, 0x1708, 0x1708, 0x1708, 0x1708, 0x1708 },
3005     //                                                                           R20     R23     R31     R39     R43     R45     R47     R49     R50     R51     R52     R54     R55     R57     R58     R59
3006     { 19, "GetDrive_TotalClusters", "GetDrive_ClusterSize", 0,                   0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x000d, 0x000c, 0x000c, 0x000c, 0x000c, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001 },
3007     { 19, "GetDrive_FreeClusters", "GetDrive_TotalClusters", 0,                  0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x000b, 0x000a, 0x000a, 0x000a, 0x000a, 0x000a, 0x000b, 0x000b, 0x000b, 0x000b, 0x000b },
3008     { 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)
3009 
3010     { 19, "time", "GetTimeOfSystem_FW", 0,                                       0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,-0x002c,-0x002d,-0x0c2d,-0x0c2d,-0x0c2d,-0x0e2d },
3011     { 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)
3012     { 19, "IsInvalidTime", "GetValidSystemCalender", 0,                          0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008, 0x4008 },
3013     { 19, "PauseTimeOfSystem", "GetValidSystemCalender", 0,                      0x400e, 0x400e, 0x400e, 0x400e, 0x400e, 0x400e, 0x400e, 0x400e, 0x400e, 0x400e, 0x400e, 0x400e, 0x400e, 0x400e, 0x400e, 0x400e },
3014     { 19, "ResumeTimeOfSystem", "GetValidSystemCalender", 0,                     0x4012, 0x4012, 0x4012, 0x4012, 0x4012, 0x4012, 0x4012, 0x4012, 0x4012, 0x4012, 0x4012, 0x4012, 0x4012, 0x4012, 0x4012, 0x4012 },
3015 
3016     { 19, "CalcLog10", "CalcLog10_FW", 0,                                       -0x100f,-0x100f,-0x100f,-0x100f,-0x100f,-0x100f,-0x100f,-0x100f,-0x100f,-0x100f,-0x100f,-0x100f,-0x100f,-0x100f,-0x100f,-0x100f },
3017     { 19, "_dfixu", "_dfix", 0,                                                  0x1f2c, 0x1f2c, 0x1f2c, 0x1f2c, 0x1f2c, 0x1f2c, 0x1f2c, 0x1f2c, 0x1f2c, 0x1f2c, 0x1f2c, 0x1f2c, 0x1f2c, 0x1f2c, 0x1f2c, 0x1f2c },
3018     { 19, "_dsub", "_sqrt", 0,                                                   0x165d, 0x165d, 0x165d, 0x165d, 0x165d, 0x165d, 0x165d, 0x165d, 0x165d, 0x165d, 0x165d, 0x165d, 0x165d, 0x165d, 0x165d, 0x165d },
3019     { 19, "_drsb", "_sqrt", 0,                                                  -0x1114,-0x1114,-0x1114,-0x1114,-0x1114,-0x1114,-0x1106,-0x1106,-0x1106,-0x1106,-0x1106,-0x1106,-0x1106,-0x1106,-0x1106,-0x1106 },
3020     { 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
3021     { 19, "_dcmp_reverse", "_dmul", 0,                                           0x2e80, 0x2e80, 0x3580, 0x3580, 0x3580, 0x3580, 0x3474, 0x3474, 0x3474, 0x3474, 0x3474, 0x3474, 0x3474, 0x3474, 0x3474, 0x3474 },
3022     { 19, "_dcmp", "_dfltu", 0,                                                  0x1003, 0x1003, 0x1003, 0x1003, 0x1003, 0x1003, 0x1003, 0x1003, 0x1003, 0x1003, 0x1003, 0x1003, 0x1003, 0x1003, 0x1003, 0x1003 },
3023     { 19, "_safe_sqrt", "_dadd", 0,                                              0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000,-0x1d13,-0x1d13,-0x1d13,-0x1d13,-0x1d13,-0x1d13,-0x1d13,-0x1d13,-0x1d13,-0x1d13 },
3024     { 19, "_safe_sqrt", "_log", 0,                                              -0x132f,-0x132f,-0x1695,-0x132f,-0x132f,-0x132f, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000 },
3025     { 19, "_safe_sqrt", "_log", 0,                                               0xf000, 0xf000,-0x132f,-0x1695, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000 },
3026     { 19, "_ddiv", "_dadd", 0,                                                   0x10aa, 0x10aa, 0x10aa, 0x10aa, 0x10aa, 0x10c3, 0x10b6, 0x10b6, 0x10b6, 0x10b6, 0x10b6, 0x10b6, 0x10b6, 0x10b6, 0x10b6, 0x10b6 },
3027     { 19, "_ffixu", "_ffix", 0,                                                  0x311d, 0x311d, 0x311d, 0x311d, 0x311d, 0x311d, 0x311d, 0x311d, 0x311d, 0x311d, 0x311d, 0x311d, 0x311d, 0x311d, 0x311d, 0x311d },
3028     { 19, "_ffltu", "_fflt", 0,                                                  0x400d, 0x400d, 0x400d, 0x400d, 0x400d, 0x400d, 0x400d, 0x400d, 0x400d, 0x400d, 0x400d, 0x400d, 0x400d, 0x400d, 0x400d, 0x400d },
3029     { 19, "_f2d", "_fdiv", 0,                                                    0xf000,-0x301f,-0x301f,-0x301f,-0x301f,-0x301f,-0x3061,-0x3061,-0x3061,-0x3061,-0x3061,-0x3061,-0x3061,-0x3061,-0x3061,-0x3061 },
3030     { 19, "_f2d", "_fdiv", 0,                                                   -0x306b,-0x306b,-0x306b,-0x306b,-0x306b,-0x306b, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000 },
3031 
3032     { 21, "add_ptp_handler", (char*)find_add_ptp_handler, 0 },
3033     { 21, "apex2us", (char*)find_apex2us, 0 },
3034     { 21, "mkdir", (char*)find_mkdir, 0 },
3035     { 21, "_pow", (char*)find_pow, 0 },
3036     { 21, "rand", (char*)find_rand, 0 },
3037     { 21, "get_ptp_file_buf", (char*)find_get_ptp_file_buf, 0 },
3038 
3039     { 22, "closedir", (char*)find_closedir, 0 },
3040     { 22, "PT_PlaySound", (char*)find_PT_PlaySound, 0 },
3041     { 22, "getImageDirName", (char*)find_getImageDirName, 0 },
3042     { 22, "GetImageFolder", (char*)find_GetImageFolder, 0 },
3043     { 22, "GetDrive_ClusterSize", (char*)find_GetDrive_ClusterSize, 0 },
3044     { 22, "GetDrive_TotalClusters", (char*)find_GetDrive_TotalClusters, 0 },
3045     { 22, "srand", (char*)find_srand, 0 },
3046     { 22, "Restart", (char*)find_Restart, 0 },
3047     { 22, "DisplayBusyOnScreen", (char*)find_DisplayBusyOnScreen, 0 },
3048     { 22, "UndisplayBusyOnScreen", (char*)find_UndisplayBusyOnScreen, 0 },
3049     { 22, "CreateDialogBox", (char*)find_CreateDialogBox, 0 },
3050     { 22, "DisplayDialogBox", (char*)find_DisplayDialogBox, 0 },
3051     { 22, "add_ui_to_dialog", (char*)find_add_ui_to_dialog, 0 },
3052     { 22, "get_string_by_id", (char*)find_get_string_by_id, 0 },
3053     { 22, "get_fstype", (char*)find_get_fstype, 0 },
3054     { 22, "malloc_strictly", (char*)find_malloc_strictly, 0 },
3055     { 22, "SetHPTimerAfterTimeout", (char*)find_sethptimeraftertimeout, 0},
3056     { 22, "GetCurrentMachineTime", (char*)find_getcurrentmachinetime, 0},
3057     { 22, "get_self_task_errno_pointer", (char*)find_get_self_task_errno_pointer, 0},
3058     { 22, "get_nd_value", (char*)find_get_nd_value, 0},
3059     { 22, "get_current_nd_value", (char*)find_get_current_nd_value, 0},
3060     { 22, "get_current_deltasv", (char*)find_get_current_deltasv, 0},
3061     { 22, "GetBaseSv", (char*)find_GetBaseSv, 0},
3062     { 22, "DoMovieFrameCapture", (char*)find_DoMovieFrameCapture, 0},
3063     { 22, "get_ptp_buf_size", (char*)find_get_ptp_buf_size, 0},
3064     { 22, "Remove", (char*)find_Remove, 0},
3065     { 22, "EnableDispatch", (char*)find_dispatch_funcs, 0},
3066     { 22, "DisableDispatch", (char*)find_dispatch_funcs, 1},
3067     { 22, "GetTimeFromRTC", (char*)find_GetTimeFromRTC_and_more, 0},
3068     { 22, "GetValidSystemCalender", (char*)find_GetTimeFromRTC_and_more, 1},
3069     { 22, "SetValidSystemCalender", (char*)find_GetTimeFromRTC_and_more, 2},
3070     { 22, "cache_flush_and_enable", (char*)find_arm_cache_funcs, 0},
3071     { 22, "cache_clean_flush_and_disable", (char*)find_arm_cache_funcs, 1},
3072     { 22, "cache_flush_range", (char*)find_arm_cache_funcs, 2},
3073     { 22, "cache_clean_flush_range", (char*)find_arm_cache_funcs, 3},
3074     { 22, "cache_clean_range", (char*)find_arm_cache_funcs, 4},
3075     { 22, "icache_flush_and_enable", (char*)find_arm_cache_funcs2, 0},
3076     { 22, "icache_disable_and_flush", (char*)find_arm_cache_funcs2, 1},
3077     { 22, "dcache_flush_and_enable", (char*)find_arm_cache_funcs2, 2},
3078     { 22, "dcache_clean_flush_and_disable", (char*)find_arm_cache_funcs2, 3},
3079     { 22, "dcache_clean_range", (char*)find_arm_cache_funcs2, 4},
3080     { 22, "dcache_clean_flush_range", (char*)find_arm_cache_funcs2, 5},
3081     { 22, "icache_flush_range", (char*)find_arm_cache_funcs2, 6},
3082     { 22, "IsWirelessConnect", (char*)find_IsWirelessConnect, 0},
3083 
3084     //                                                                           R20     R23     R31     R39     R43     R45     R47     R49     R50     R51     R52     R54     R55     R57     R58     R59
3085     { 23, "UnregisterInterruptHandler", "HeadInterrupt1", 76,                    1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1 },
3086     { 23, "get_string_by_id", "NoError", 16,                                    99,     99,     99,     99,     99,     99,     99,     99,     99,     99,     99,     99,     99,     99,     99,     -2 },
3087     { 23, "EnableHDMIPower", "HDMIConnectCnt", 9,                               99,     99,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,},
3088     { 23, "DisableHDMIPower", "HDMIConnectCnt", 9,                              99,     99,      3,      3,      3,      3,      3,      3,      3,      3,      3,      3,      3,      3,      3,      3,},
3089     { 23, "get_nd_value", "IrisSpecification.c", 25,                            -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,},
3090     { 23, "GetUsableAvRange", "[AE]Prog Line Error!\n", 20,                      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,},
3091     { 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
3092     { 23, "DisableDispatch_low", "data abort", 7,                                0,      0,      0,      0,      0,      0,      0,      0,      0,      0,      0,      0,      0,      0,      0,      0,},
3093     { 23, "GetCurrentDriveBaseSvValue", "KeepPreviousExposureWithProgress", 5,   2,      2,      2,      2,      2,      2,      2,     99,     99,     99,     99,     99,     99,     99,     99,     99,},
3094     { 23, "cameracon_set_state", "AC:PB2Rec", 5,                                 1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1 },
3095     { 23, "cameracon_get_state", "ex:PB", 5,                                    99,     99,     -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1 },
3096     { 23, "cameracon_get_state", "exchange:PB", 5,                              99,     99,     -1,     99,     99,     99,     99,     99,     99,     99,     99,     99,     99,     99,     99,     99 }, // a1000 uses this string
3097     { 23, "dry_memzero", "pErrorAdr = 0x%lX : %02X\n\n", 6,                      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1 },
3098     { 23, "dry_memcpy", "ClassRequest, bRequest=%#02x\r\n", 4,                  -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1,     -1 },
3099 
3100     //                                                                           R20     R23     R31     R39     R43     R45     R47     R49     R50     R51     R52     R54     R55     R57     R58     R59
3101     { 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 },
3102 
3103     { 25, "", "", 0 },
3104 
3105     { 0, 0, 0, 0 }
3106 };
3107 
3108 // Find the named function in the 'func_list' array above, return index of entry
3109 int find_func(const char* name)
3110 {
3111     int i;
3112     for (i=0; func_list[i].name != 0; i++)
3113     {
3114         if (strcmp(name, func_list[i].name) == 0)
3115         {
3116             return i;
3117         }
3118     }
3119     return -1;  // Not found
3120 }
3121 
3122 // Get DryOS version specific offset
3123 int dryos_offset(firmware *fw, string_sig *sig)
3124 {
3125     switch (fw->dryos_ver)
3126     {
3127     case 20:    return sig->dryos20_offset;
3128     case 23:    return sig->dryos23_offset;
3129     case 31:    return sig->dryos31_offset;
3130     case 39:    return sig->dryos39_offset;
3131     case 43:    return sig->dryos43_offset;
3132     case 45:    return sig->dryos45_offset;
3133     case 47:    return sig->dryos47_offset;
3134     case 49:    return sig->dryos49_offset;
3135     case 50:    return sig->dryos50_offset;
3136     case 51:    return sig->dryos51_offset;
3137     case 52:    return sig->dryos52_offset;
3138     case 54:    return sig->dryos54_offset;
3139     case 55:    return sig->dryos55_offset;
3140     case 57:    return sig->dryos57_offset;
3141     case 58:    return sig->dryos58_offset;
3142     case 59:    return sig->dryos59_offset;
3143     }
3144     return 0;
3145 }
3146 
3147 //------------------------------------------------------------------------------------------------------------
3148 
3149 // Loop through firmware looking for instances of a sig string
3150 // For each one found call the check_match function to see if it matches the sig
3151 // Return 1 if match found, else return 0
3152 int fw_string_process(firmware *fw, string_sig *sig, int (*check_match)(firmware *fw, string_sig *sig, int j), int inc_eos)
3153 {
3154     int nlen = strlen(sig->ev_name);
3155     uint32_t nm0 = *((uint32_t*)sig->ev_name);
3156     uint32_t *p;
3157     int j;
3158     BufRange *br;
3159 
3160     for (br = fw->br; br != 0; br = br->next)
3161     {
3162         for (p = br->p, j = br->off; j < br->off+br->len-nlen/4; p++, j++)
3163         {
3164             if ((nm0 == *p) && (memcmp(p+1,sig->ev_name+4,nlen-4+inc_eos) == 0))
3165             {
3166                 if (check_match(fw,sig,j))
3167                     return 1;
3168             }
3169         }
3170     }
3171 
3172     return 0;
3173 }
3174 
3175 // As above; but scan the firmware byte-by-byte rather than by words
3176 // Slower; but required when strings are not stores on 32 bit boundaries
3177 int fw_string_process_unaligned(firmware *fw, string_sig *sig, int (*check_match)(firmware *fw, string_sig *sig, int j))
3178 {
3179     int nlen = strlen(sig->ev_name);
3180     char *p;
3181     int j;
3182     BufRange *br;
3183 
3184     for (br = fw->br; br != 0; br = br->next)
3185     {
3186         for (p = (char*)br->p, j = 0; j < br->len*4-nlen; p++, j++)
3187         {
3188             if (strcmp(p,sig->ev_name) == 0)
3189             {
3190                 if (check_match(fw,sig,j+br->off*4))
3191                     return 1;
3192             }
3193         }
3194     }
3195 
3196     return 0;
3197 }
3198 
3199 // Loop through the firmware from the start, calling 'check_match' for each location
3200 // If 'check_match' returns non-zero, exit returning 1.
3201 // Otherwise returns 0 - no match found.
3202 int fw_process(firmware *fw, string_sig *sig, int (*check_match)(firmware *fw, string_sig *sig, int j))
3203 {
3204     uint32_t *p;
3205     int j;
3206     BufRange *br;
3207 
3208     for (br = fw->br; br != 0; br = br->next)
3209     {
3210         for (p = br->p, j = br->off; j < br->off+br->len; p++, j++)
3211         {
3212             if (check_match(fw,sig,j))
3213                 return 1;
3214         }
3215     }
3216 
3217     return 0;
3218 }
3219 
3220 //------------------------------------------------------------------------------------------------------------
3221 
3222 // New string / signature matching functions
3223 
3224 // Sig pattern:
3225 //      Function pointer    -   DCD func
3226 //      String              -   DCB "func"
3227 // Note: 'func' may not be the target address, the sig->offset value allows selection of another function
3228 //       called at a fixed number of instructions from the 'func' address found
3229 int match_strsig1(firmware *fw, string_sig *sig, int j)
3230 {
3231     uint32_t fadr = fwval(fw,j-1);      // function address
3232     if (idx_valid(fw,adr2idx(fw,fadr))) // is function address valid
3233     {
3234         // If function address is a B, and we are following branches, then follow the first B
3235         if (sig->offset > 1) fadr = followBranch(fw, fadr, 1);
3236         // Follow any subsequent branch at the given offset
3237         fadr = followBranch2(fw, fadr, sig->offset);
3238         fwAddMatch(fw,fadr,32,0,101);
3239         return 1;
3240     }
3241     return 0;
3242 }
3243 
3244 // Sig pattern:
3245 //      String pointer      -       DCD str
3246 //      Function pointer    -       DCD func
3247 //                ...
3248 //      String              -   str DCB "func"
3249 // Note: 'func' may not be the target address, the offset value allows selection of another function
3250 //       called at a fixed number of instructions from the 'func' address found
3251 int match_strsig2a(firmware *fw, int k, uint32_t sadr, uint32_t offset)
3252 {
3253     if (fwval(fw,k) == sadr)                // pointer to string?
3254     {
3255         uint32_t fadr = fwval(fw,k+1);      // function address
3256         if (idx_valid(fw,adr2idx(fw,fadr))) // is function address valid
3257         {
3258             uint32_t bfadr = followBranch2(fw, fadr, offset);
3259             if ((offset <= 1) || (bfadr != fadr))
3260             {
3261                 fwAddMatch(fw,bfadr,32,0,102);
3262                 return 1;
3263             }
3264         }
3265     }
3266     return 0;
3267 }
3268 int match_strsig2(firmware *fw, string_sig *sig, int j)
3269 {
3270     // Note - 'j' is byte offset in firmware not instruction index (called from fw_string_process_unaligned)
3271     return search_fw(fw, match_strsig2a, fw->base + j, sig->offset, 2);
3272 }
3273 
3274 // Sig pattern:
3275 //      Load Func Address   -   ADR Rx, func
3276 //      Load String Address -   ADR Rx, "func"
3277 //      Branch              -   BL
3278 //              ...
3279 //      String              -   DCB "func"
3280 // or
3281 //      Load Func Address   -   ADR Rx, func
3282 //                              B   loc
3283 //              ...
3284 //                          loc:
3285 //      Load String Address -   ADR    Rx, "func"
3286 //      Branch              -   BL
3287 //              ...
3288 //      String              -   DCB "func"
3289 // 'sadr' = address of "func" string
3290 // Note: 'func' may not be the target address, the offset value allows selection of another function
3291 //       called at a fixed number of instructions from the 'func' address found
3292 int match_strsig3a(firmware *fw, int k, uint32_t sadr, uint32_t offset)
3293 {
3294     if (isADR_PC(fw,k+1) &&    // ADR ?
3295         isBorBL(fw,k+2))       // B or BL ?
3296     {
3297         uint32_t padr = ADR2adr(fw,k+1);    // get address pointed to by 2nd ADR instructioin
3298         if (padr == sadr)                   // does it match target string
3299         {
3300             int j2 = k;
3301             int found = 0;
3302             if (isADR_PC(fw,k))             // ADR ?
3303                 found = 1;
3304             else
3305             {
3306                 // May be DCD block between 1st and 2nd ADR
3307                 for (j2 = k-2; j2 >= 0 && j2 >= k-4096; j2--)
3308                 {
3309                     if (isADR_PC(fw,j2) &&  // ADR ?
3310                         isB(fw,j2+1))       // B
3311                     {
3312                         uint32_t fa = idx2adr(fw,j2+1);
3313                         fa = followBranch(fw,fa,1);
3314                         if (adr2idx(fw,fa) == k+1)
3315                         {
3316                             found = 1;
3317                             break;
3318                         }
3319                     }
3320                 }
3321             }
3322             if (found)
3323             {
3324                 uint32_t fadr = ADR2adr(fw,j2);
3325                 if (offset > 1) fadr = followBranch(fw, fadr, 1);
3326                 fadr = followBranch2(fw, fadr, offset);
3327                 fwAddMatch(fw,fadr,32,0,103);
3328                 return 1;
3329             }
3330         }
3331     }
3332     return 0;
3333 }
3334 int match_strsig3(firmware *fw, string_sig *sig, int j)
3335 {
3336     return search_fw(fw, match_strsig3a, idx2adr(fw,j), sig->offset, 3);
3337 }
3338 
3339 // Sig pattern:
3340 //      Save Regs           -   STMFD
3341 //                ... (offset)
3342 //      Load String Address -   ADR Rx, "func"
3343 //                ...
3344 //      String              -   DCB "func"
3345 int match_strsig4a(firmware *fw, int k, uint32_t sadr, uint32_t offset)
3346 {
3347     if (isSTMFD(fw,k) &&        // STMFD
3348         isADR_PC(fw,k+offset))  // ADR ?
3349     {
3350         uint32_t padr = ADR2adr(fw,k+offset);
3351         if (padr == sadr)
3352         {
3353             uint32_t fadr = idx2adr(fw,k);
3354             fwAddMatch(fw,fadr,32,0,104);
3355             return 1;
3356         }
3357     }
3358     return 0;
3359 }
3360 int match_strsig4(firmware *fw, string_sig *sig, int j)
3361 {
3362     return search_fw(fw, match_strsig4a, idx2adr(fw,j), sig->offset, sig->offset+1);
3363 }
3364 
3365 // Sig pattern:
3366 //      Load Func Address   -   LDR Rx, =func
3367 //      Load String Address -   xDR Rx, "func"  (LDR or ADR)
3368 //      Branch              -   BL
3369 //              ...
3370 //      String              -   DCB "func"
3371 // or
3372 //      Load Func Address   -   LDR Rx, =func
3373 //                              B   loc
3374 //              ...
3375 //                          loc:
3376 //      Load String Address -   xDR Rx, "func"  (LDR or ADR)
3377 //      Branch              -   BL
3378 //              ...
3379 //      String              -   DCB "func"
3380 static int dryos_ofst;
3381 int match_strsig5a(firmware *fw, int k, uint32_t sadr, uint32_t offset)
3382 {
3383     if ((isADR_PC(fw,k+1) || isLDR_PC(fw,k+1)) &&   // LDR or ADR ?
3384         isBorBL(fw,k+2))                            // B or BL ?
3385     {
3386         uint32_t padr;
3387         if (isLDR_PC(fw,k+1))                       // LDR ?
3388             padr = LDR2val(fw,k+1);
3389         else
3390             padr = ADR2adr(fw,k+1);
3391         if (padr == sadr)
3392         {
3393             int j2 = k;
3394             int found = 0;
3395             if (isLDR_PC(fw,k))                     // LDR ?
3396                 found = 1;
3397             else
3398             {
3399                 for (j2 = k-2; j2 >= 0 && j2 >= k-4096; j2--)
3400                 {
3401                     if (isLDR_PC(fw,j2) &&  // LDR ?
3402                         isB(fw,j2+1))       // B
3403                     {
3404                         if (idxFollowBranch(fw,j2+1,1) == k+1)
3405                         {
3406                             found = 1;
3407                             break;
3408                         }
3409                     }
3410                 }
3411             }
3412             if (found)
3413             {
3414                 uint32_t fadr = LDR2val(fw,j2);
3415                 if (offset > 1) fadr = followBranch(fw, fadr, 1);
3416                 fadr = followBranch2(fw, fadr, offset);
3417                 if (dryos_ofst != 0)
3418                 {
3419                     uint32_t fadr2 = followBranch(fw, fadr, dryos_ofst);
3420                     if (fadr == fadr2) return 0;
3421                     fadr = fadr2;
3422                 }
3423                 fwAddMatch(fw,fadr,32,0,105);
3424                 return 1;
3425             }
3426         }
3427     }
3428     return 0;
3429 }
3430 int match_strsig5(firmware *fw, string_sig *sig, int j)
3431 {
3432     dryos_ofst = dryos_offset(fw,sig);
3433     return search_fw(fw, match_strsig5a, idx2adr(fw,j), sig->offset, 3);
3434 }
3435 
3436 // Sig pattern:
3437 //    Function immediately preceeding string
3438 int match_strsig6(firmware *fw, __attribute__ ((unused))string_sig *sig, int j)
3439 {
3440     int j1 = find_inst_rev(fw, isSTMFD_LR, j-1, j-1);
3441     if (j1 > 0)
3442     {
3443         uint32_t fadr = idx2adr(fw,j1);
3444         fwAddMatch(fw,fadr,32,0,106);
3445         return 1;
3446     }
3447 
3448     return 0;
3449 }
3450 
3451 // Sig pattern:
3452 //      Str ref -   xDRnn Rx, =str_ptr
3453 //            ...
3454 //                  BL  func
3455 //            ...
3456 //      String      DCB "str"
3457 int match_strsig7a(firmware *fw, int k, uint32_t sadr, uint32_t offset)
3458 {
3459     if (isADR_PC_cond(fw,k) || isLDR_PC_cond(fw,k)) // LDR or ADR ?
3460     {
3461         uint32_t padr;
3462         if (isLDR_PC_cond(fw,k)) // LDR ?
3463             padr = LDR2val(fw,k);
3464         else
3465             padr = ADR2adr(fw,k);
3466         if (padr == sadr)
3467         {
3468             int j2 = find_inst(fw, isBL, k+1, 10);
3469             if (j2 > 0)
3470             {
3471                 uint32_t fa = idx2adr(fw,j2);
3472                 fa = followBranch2(fw,fa,offset);
3473                 fwAddMatch(fw,fa,32,0,107);
3474                 return 1;
3475             }
3476         }
3477     }
3478     return 0;
3479 }
3480 int match_strsig7(firmware *fw, string_sig *sig, int j)
3481 {
3482     return search_fw(fw, match_strsig7a, idx2adr(fw,j), sig->offset, 2);
3483 }
3484 
3485 // Sig pattern:
3486 //      Special case for WriteSDCard
3487 int ofst;
3488 int match_strsig8(firmware *fw, __attribute__ ((unused))string_sig *sig, int j)
3489 {
3490     int j1;
3491     uint32_t u1;
3492     for (j1=j-2; j1<j+8; j1++)
3493     {
3494         uint32_t fadr = idx2adr(fw,j1);
3495         u1 = fwval(fw,j1);
3496         if ((u1 >= fw->base) || ((u1 >= fw->base2) && (u1 < fw->base2 + fw->size2*4)))  // pointer ??
3497         {
3498             int j2;
3499             for (j2=j1-1; j2>=j1-1000 && j2>=0; j2--)
3500             {
3501                 if (isLDR_PC(fw,j2) && (LDR2adr(fw,j2) == fadr))    // LDR ?
3502                 {
3503                     if ((isSTR(fw,j2+1) && (fwOp2(fw,j2+1) == ofst)) ||    // STR ?
3504                         (isSTR(fw,j2+2) && (fwOp2(fw,j2+2) == ofst)))      // STR ?
3505                     {
3506                         fadr = fwval(fw,j1);
3507                         if (idx_valid(fw,adr2idx(fw,fadr)))
3508                         {
3509                             fwAddMatch(fw,fadr,32,0,108);
3510                             return 1;
3511                         }
3512                     }
3513                 }
3514             }
3515         }
3516     }
3517 
3518     return 0;
3519 }
3520 int find_strsig8(firmware *fw, string_sig *sig)
3521 {
3522     uint32_t fadr = 0;
3523     int srch = 20;
3524 
3525     // Find "UpdateMBROnFlash" code
3526     int j = get_saved_sig(fw,"UpdateMBROnFlash");
3527     if (j >= 0)
3528     {
3529         fadr = func_names[j].val;
3530     }
3531     else
3532     {
3533         j = get_saved_sig(fw,"MakeSDCardBootable");
3534         if (j >= 0)
3535         {
3536             fadr = func_names[j].val;
3537             srch = 32;
3538         }
3539     }
3540 
3541     if (fadr == 0) return 0;
3542 
3543     int idx = adr2idx(fw, fadr);
3544     ofst = -1;
3545 
3546     for (j=idx+srch; j<idx+srch+12; j++)
3547     {
3548         if (isLDR(fw,j) && isLDR(fw,j+1) && isLDR(fw,j+2))
3549         {
3550             ofst = fwOp2(fw,j) + fwOp2(fw,j+1) + fwOp2(fw,j+2);
3551             break;
3552         }
3553     }
3554 
3555     if (ofst == -1) return 0;
3556 
3557     return fw_string_process(fw, sig, match_strsig8, 1);
3558 }
3559 
3560 // Sig pattern:
3561 //      Func is B/BL @ offset from previous found func
3562 //          prev_func
3563 //              ... (offset)
3564 //              BL    func
3565 int find_strsig9(firmware *fw, string_sig *sig)
3566 {
3567     int j = get_saved_sig(fw,sig->ev_name);
3568     if (j >= 0)
3569     {
3570         if (func_names[j].val != 0)
3571         {
3572             int ofst = dryos_offset(fw, sig);
3573             uint32_t fadr = followBranch(fw, func_names[j].val+ofst*4, 0xF1000001);
3574             if ((sig->offset == -1) || (fadr != func_names[j].val+ofst*4))
3575             {
3576                 uint32_t fadr2 = fadr;
3577                 if (sig->offset != -1) fadr2 = followBranch2(fw, fadr2, sig->offset);
3578                 if ((sig->offset <= 0) || (fadr2 != fadr))
3579                 {
3580                     fwAddMatch(fw,fadr2,32,0,109);
3581                     return 1;
3582                 }
3583             }
3584         }
3585     }
3586 
3587     return 0;
3588 }
3589 
3590 // Sig pattern:
3591 //      Func            -   func
3592 //            .... (offset)
3593 //      Ref to string   -       ADR Rx, str
3594 //            ....
3595 //      String          -       DCB "str"
3596 int match_strsig11(firmware *fw, string_sig *sig, int j)
3597 {
3598     int ofst = dryos_offset(fw, sig);
3599 
3600     uint32_t sadr = idx2adr(fw,j);        // string address
3601     int j1;
3602     for (j1 = j-1; j1 >= 0; j1--)
3603     {
3604         if (isADR_PC_cond(fw,j1))   // ADR ?
3605         {
3606             uint32_t padr = ADR2adr(fw,j1);
3607             if (padr == sadr)
3608             {
3609                 uint32_t fadr = idx2adr(fw,j1-ofst);
3610                 uint32_t bfadr = followBranch(fw,fadr,sig->offset);
3611                 // special case for 'set_control_event'
3612                 int found = 0;
3613                 if (strcmp(sig->name,"set_control_event") == 0)
3614                 {
3615                     int j2 = j1 - ofst;
3616                     if (isBL_cond(fw,j2) &&                                             // BLxx
3617                         isLDR_SP(fw,j2+1) && (fwRd(fw,j2+1) == 0) &&                    // LDR R0,[SP,x]
3618                         isBL(fw,j2+2) &&                                                // BL
3619                         isMOV(fw,j2+3) && (fwRd(fw,j2+3) == 4) && (fwRn(fw,j2+3) == 0)) // LDR R4, R0
3620                     {
3621                         found = 1;
3622                     }
3623                 }
3624                 else
3625                     found = 1;
3626                 if (found && ((sig->offset == 0) || (bfadr != fadr)))
3627                 {
3628                     fwAddMatch(fw,bfadr,32,0,111);
3629                     return 1;
3630                 }
3631             }
3632         }
3633     }
3634 
3635     return 0;
3636 }
3637 
3638 // Sig pattern:
3639 //      Func is referenced in 'CreateJumptable'
3640 //          LDR R1, =func
3641 //          STR R1, [R0,nnn]
3642 //      nnn - dryos version dependant offset
3643 int find_strsig12(firmware *fw, string_sig *sig)
3644 {
3645     int j = get_saved_sig(fw,"CreateJumptable");
3646 
3647     int ofst = dryos_offset(fw, sig);
3648 
3649     if (ofst == 0) return 0;
3650 
3651     if (j >= 0)
3652     {
3653         if (func_names[j].val != 0)
3654         {
3655             int idx = adr2idx(fw, func_names[j].val);
3656             for(; !isBX_LR(fw,idx); idx++)  // BX LR
3657             {
3658                 if (((fwval(fw,idx+1) & 0xFFFFF000) == 0xE5801000) && // STR R1,[R0,nnn]
3659                     (fwOp2(fw,idx+1) == ofst))
3660                 {
3661                     uint32_t fadr = LDR2val(fw,idx);
3662                     uint32_t bfadr = followBranch2(fw,fadr,sig->offset);
3663                     if ((sig->offset <= 1) || ((bfadr != fadr) && ((fw->buf[adr2idx(fw,fadr)] & 0xFFFF0000) == 0xE92D0000)))
3664                     {
3665                         fwAddMatch(fw,bfadr,32,0,112);
3666                         return 1;
3667                     }
3668                 }
3669                 else if (isB(fw,idx))    // B
3670                 {
3671                     idx = adr2idx(fw,followBranch(fw,idx2adr(fw,idx),1)) - 1;
3672                 }
3673             }
3674         }
3675     }
3676 
3677     return 0;
3678 }
3679 
3680 // Sig pattern:
3681 //      Func    -   func
3682 //          ... (offset)
3683 //      Str ref -       LDR Rx, =str_ptr
3684 //          ...
3685 //      Str ptr -       DCD str_ptr
3686 //          ...
3687 //      Str ptr -   str_ptr
3688 //                      DCD str
3689 //          ...
3690 //      String          DCB "str"
3691 int match_strsig13a(firmware *fw, int k, uint32_t sadr, uint32_t offset)
3692 {
3693     if (fwval(fw,k) == sadr)    // string ptr
3694     {
3695         uint32_t padr = idx2adr(fw,k);      // string ptr address
3696         int j2;
3697         for (j2 = k-1; j2 >= 0; j2--)
3698         {
3699             if (fwval(fw,j2) == padr)       // string ptr address
3700             {
3701                 uint32_t ppadr = idx2adr(fw,j2);        // string ptr ptr address
3702                 int j3;
3703                 for (j3 = j2-1; j3 >= 0; j3--)
3704                 {
3705                     if (isLDR_PC(fw,j3) && (LDR2adr(fw,j3) == ppadr))
3706                     {
3707                         uint32_t fadr = idx2adr(fw,j3-offset);
3708                         fwAddMatch(fw,fadr,32,0,113);
3709                         return 1;
3710                     }
3711                 }
3712             }
3713         }
3714     }
3715     return 0;
3716 }
3717 int match_strsig13(firmware *fw, string_sig *sig, int j)
3718 {
3719     // Note - 'j' is offset in firmware not instruction index (called from fw_string_process_unaligned)
3720     return search_fw(fw, match_strsig13a, fw->base + j, sig->offset, 1);
3721 }
3722 
3723 // Sig pattern:
3724 //                  BL  func
3725 //            ...
3726 //      Str ref -   xDR Rx, =str_ptr
3727 //            ...
3728 //      String      DCB "str"
3729 // dryos_ofst: search range limit for the previous bl instruction
3730 int match_strsig15a(firmware *fw, int k, uint32_t sadr, uint32_t offset)
3731 {
3732     if (isADR_PC_cond(fw,k) || isLDR_PC_cond(fw,k))   // LDR or ADR ?
3733     {
3734         uint32_t padr;
3735         if (isLDR_PC_cond(fw,k)) // LDR ?
3736             padr = LDR2val(fw,k);
3737         else
3738             padr = ADR2adr(fw,k);
3739         if (padr == sadr)
3740         {
3741             int j2 = find_inst_rev(fw, isBL, k-1, dryos_ofst);
3742             if (j2 != -1)
3743             {
3744                 // cams with code copied to RAM: use RAM address
3745                 j2 = idxcorr(fw, j2);
3746                 uint32_t fa = idx2adr(fw,j2);
3747                 fa = followBranch2(fw,fa,offset);
3748                 fwAddMatch(fw,fa,32,0,115);
3749                 return 1;
3750             }
3751         }
3752     }
3753     return 0;
3754 }
3755 int match_strsig15(firmware *fw, string_sig *sig, int j)
3756 {
3757     dryos_ofst = dryos_offset(fw,sig);
3758     if (dryos_ofst == 0) dryos_ofst = 50;
3759     return search_fw(fw, match_strsig15a, idx2adr(fw,j), sig->offset, 1);
3760 }
3761 
3762 // Sig pattern:
3763 //      Function immediately preceeding usage of hex value
3764 int match_strsig16(firmware *fw, string_sig *sig, int j)
3765 {
3766     uint32_t nm0 = *((uint32_t*)sig->ev_name);
3767 
3768     if (isADR_PC_cond(fw,j) || isLDR_PC_cond(fw,j))   // LDR or ADR ?
3769     {
3770         uint32_t padr;
3771         if (isLDR_PC_cond(fw,j)) // LDR ?
3772             padr = LDR2val(fw,j);
3773         else
3774             padr = ADR2adr(fw,j);
3775         if (padr == nm0)
3776         {
3777             int j2 = find_inst_rev(fw, isSTMFD_LR, j-1, 50);
3778             if (j2 > 0)
3779             {
3780                 uint32_t fa = idx2adr(fw,j2);
3781                 fwAddMatch(fw,fa,32,0,116);
3782                 return 1;
3783             }
3784         }
3785     }
3786 
3787     return 0;
3788 }
3789 
3790 // Sig pattern:
3791 //      Special case for ScreenLock & ScreenUnlock
3792 int find_strsig17(firmware *fw, string_sig *sig)
3793 {
3794     int j = get_saved_sig(fw,"StartRecModeMenu");
3795 
3796     if (j >= 0)
3797     {
3798         if (func_names[j].val != 0)
3799         {
3800             int idx = adr2idx(fw, func_names[j].val);
3801             int k = 0;
3802             if (fw->dryos_ver < 58)
3803             {
3804                 if (isLDR_PC(fw,idx-3) && isMOV_immed(fw,idx-2) && isB(fw,idx-1))
3805                 {
3806                     k = adr2idx(fw,LDR2val(fw,idx-3));
3807                 }
3808                 else if (isMOV_immed(fw,idx-3) && isADR_PC(fw,idx-2) && isB(fw,idx-1))
3809                 {
3810                     k = adr2idx(fw,ADR2adr(fw,idx-2));
3811                 }
3812             }
3813             else
3814             {
3815                 int l = find_inst_rev(fw, isBL, idx-1, 4);
3816                 if (l > 0)
3817                 {
3818                     if (isLDR_PC(fw,l-2) && isMOV_immed(fw,l-1))
3819                     {
3820                         k = adr2idx(fw,LDR2val(fw,l-2));
3821                     }
3822                 }
3823             }
3824             if (k != 0)
3825             {
3826                 uint32_t fadr = 0;
3827                 if (strcmp(sig->name,"ScreenLock") == 0)
3828                     fadr = followBranch(fw,idx2adr(fw,k+1),0x01000001);
3829                 else
3830                 {
3831                     k = find_inst(fw, isLDMFD, k+1, 60);
3832                     if (fw->dryos_ver < 58)
3833                     {
3834                         fadr = followBranch(fw,idx2adr(fw,k-1),0x01000001);
3835                     }
3836                     else
3837                     {
3838                         k = find_inst_rev(fw, isBL, k-1, 4);
3839                         if (k > 0)
3840                         {
3841                             fadr = followBranch(fw,idx2adr(fw,k),0x01000001);
3842                         }
3843                     }
3844                 }
3845                 if (fadr > 0)
3846                 {
3847                     fwAddMatch(fw,fadr,32,0,117);
3848                     return 1;
3849                 }
3850             }
3851         }
3852     }
3853 
3854     return 0;
3855 }
3856 
3857 // Sig pattern:
3858 //      Func is offset from previously found func
3859 //          prev_func
3860 //              ... (offset, less than 0xff)
3861 //          func
3862 // dryos_offset to be encoded as: 0xQRPP
3863 // PP) offset, 0x00...0xff, in words
3864 // Q) 'previous instruction flag': 0 for LDMFD, 1 for B, 2 for conditional B, 3 for mov pc,lr, 4 for bx lr
3865 // R) 'additional gap size': 0x0 ... 0xf, to skip an additional gap, in words
3866 // offset is negative if dryos_offset is negative
3867 int find_strsig19(firmware *fw, string_sig *sig)
3868 {
3869     int j = get_saved_sig(fw,sig->ev_name);
3870     if (j >= 0)
3871     {
3872         if (func_names[j].val != 0) // address, not idx
3873         {
3874             int ofst = dryos_offset(fw, sig);
3875             int neg = 1;
3876             if (ofst<0)
3877             {
3878                 neg=-1;
3879                 ofst=-ofst;
3880             }
3881             int addoffs = (ofst & 0xf00)>>8;
3882             uint32_t fadr = func_names[j].val+neg*(ofst&0xff)*4;
3883             int k = 0;
3884             switch ((ofst&0xf000)>>12)
3885             {
3886                 case 0: k = isLDMFD_PC(fw, adr2idx(fw, fadr)-1-addoffs); break;
3887                 case 1: k = isB(fw, adr2idx(fw, fadr)-1-addoffs); break;
3888                 case 2: k = ((fwval(fw, adr2idx(fw, fadr)-1-addoffs) & 0x0f000000) == 0x0a000000); break; // B cond.
3889                 case 3: k = (fwval(fw, adr2idx(fw, fadr)-1-addoffs) == 0xE1A0F00E); break; // mov pc, lr
3890                 case 4: k = (fwval(fw, adr2idx(fw, fadr)-1-addoffs) == 0xE12FFF1E); break; // bx lr
3891                 default: return 0;
3892             }
3893             if (k)
3894             {
3895                 fwAddMatch(fw,fadr,32,0,119);
3896                 return 1;
3897             }
3898         }
3899     }
3900 
3901     return 0;
3902 }
3903 
3904 // Sig pattern:
3905 //      Str ref -   xDRnn Rx, =str_ptr
3906 //            ...
3907 //                  BL  func
3908 //            ...
3909 //      String      DCB "str"
3910 // offset: interpreted as max search distance
3911 // dryos_ofst: 0 for 1st B/BL after str ref, 1 for 2nd, etc.; -1 for 1st preceding, etc...; disable with 99
3912 // based on method 7
3913 int match_strsig23a(firmware *fw, int k, uint32_t sadr, uint32_t maxdist)
3914 {
3915     if (isADR_PC_cond(fw,k) || isLDR_PC_cond(fw,k)) // LDR or ADR ?
3916     {
3917         uint32_t padr;
3918         if (isLDR_PC_cond(fw,k)) // LDR ?
3919             padr = LDR2val(fw,k);
3920         else
3921             padr = ADR2adr(fw,k);
3922         if (padr == sadr)
3923         {
3924             int j2;
3925             if (dryos_ofst < 0)
3926             {
3927                 j2 = find_Nth_inst_rev(fw, isBorBL, k, maxdist, -dryos_ofst);
3928             }
3929             else
3930             {
3931                 j2 = find_Nth_inst(fw, isBorBL, k+1, maxdist, dryos_ofst+1);
3932             }
3933             if (j2 > 0)
3934             {
3935                 uint32_t fa = idx2adr(fw,j2);
3936                 fa = followBranch2(fw,fa,0x01000001);
3937                 fwAddMatch(fw,fa,32,0,123);
3938                 return 1;
3939             }
3940         }
3941     }
3942     return 0;
3943 }
3944 int match_strsig23(firmware *fw, string_sig *sig, int j)
3945 {
3946     dryos_ofst = dryos_offset(fw,sig);
3947 
3948     if (dryos_ofst == 99)
3949         return 0;
3950 
3951     return search_fw(fw, match_strsig23a, idx2adr(fw,j), sig->offset, 2);
3952 }
3953 
3954 // Sig pattern:
3955 //      Func            -   func
3956 //            .... [offset]
3957 //      Nth instruction backwards from string ref
3958 //      Ref to string   -       LDR Rx, pstr
3959 //            ....
3960 //      Ptr to string   -       DCD pstr
3961 // dryos_offset to be encoded as: 0xQNPP
3962 // P) additional offset
3963 // Q) instruction to locate: 0 for STMFD_LR, 0xf to disable
3964 // N) search the instruction this many times - 1 (i.e. 0 = first instruction backwards)
3965 // prev instruction search range is limited by sig->offset
3966 // the reference to the string has to occur within 256 words (fixed range)
3967 // based on method 104 of finsig_vxworks
3968 int match_strsig24(firmware *fw, string_sig *sig, int j)
3969 {
3970 
3971     int ofst = dryos_offset(fw, sig);
3972     int prinst = (ofst&0xf000)>>12;
3973     int ninst = ((ofst&0xf00)>>8)+1;
3974     ofst &= 0xff;
3975     void *instid;
3976     switch (prinst) {
3977         case 0:
3978             instid = (void*)isSTMFD_LR;
3979             break;
3980         default:
3981             return 0;
3982     }
3983 
3984     uint32_t sadr = idx2adr(fw,j);        // string address
3985     int j1;
3986     for (j1 = j; j1 >= MAX(j-256,0); j1--)
3987     {
3988         if (isLDR(fw,j1))   // LDR ?
3989         {
3990             uint32_t pval = LDR2val(fw,j1);
3991             if (pval == sadr)
3992             {
3993                 int j2 = find_Nth_inst_rev(fw,instid,j1-1,sig->offset,ninst);
3994                 if (j2>0)
3995                 {
3996                     fwAddMatch(fw,idx2adr(fw,j2-ofst),32,0,124);
3997                     return 1;
3998                 }
3999             }
4000         }
4001         else if (isADR_PC(fw,j1))   // ADR ?
4002         {
4003             uint32_t pval = ADR2adr(fw,j1);
4004             if (pval == sadr)
4005             {
4006                 int j2 = find_Nth_inst_rev(fw,instid,j1-1,sig->offset,ninst);
4007                 if (j2>0)
4008                 {
4009                     fwAddMatch(fw,idx2adr(fw,j2-ofst),32,0,124);
4010                     return 1;
4011                 }
4012             }
4013         }
4014     }
4015 
4016     return 0;
4017 }
4018 
4019 // Call processing function based on type
4020 int find_strsig(firmware *fw, string_sig *sig)
4021 {
4022     switch (sig->type)
4023     {
4024     case 1:     return fw_string_process(fw, sig, match_strsig1, 1);
4025     case 2:     return fw_string_process_unaligned(fw, sig, match_strsig2);
4026     case 3:     return fw_string_process(fw, sig, match_strsig3, 1);
4027     case 4:     return fw_string_process(fw, sig, match_strsig4, 1);
4028     case 5:     return fw_string_process(fw, sig, match_strsig5, 1);
4029     case 6:     return fw_string_process(fw, sig, match_strsig6, 1);
4030     case 7:     return fw_string_process(fw, sig, match_strsig7, 1);
4031     case 8:     return find_strsig8(fw, sig);
4032     case 9:     return find_strsig9(fw, sig);
4033     case 11:    return fw_string_process(fw, sig, match_strsig11, 0);
4034     case 12:    return find_strsig12(fw, sig);
4035     case 13:    return fw_string_process_unaligned(fw, sig, match_strsig13);
4036     case 15:    return fw_string_process(fw, sig, match_strsig15, 1);
4037     case 16:    return fw_process(fw, sig, match_strsig16);
4038     case 17:    return find_strsig17(fw, sig);
4039     case 19:    return find_strsig19(fw, sig);
4040     case 20:
4041         {
4042             int j = find_saved_sig(sig->ev_name);
4043             if (j >= 0)
4044             {
4045                 uint32_t fadr = followBranch2(fw,func_names[j].val,sig->offset);
4046                 fwAddMatch(fw,fadr,32,0,120);
4047                 return 1;
4048             }
4049             return 0;
4050         }
4051     case 21:    return fw_process(fw, sig, (int (*)(firmware*, string_sig*, int))(sig->ev_name));
4052     case 22:    return ((int (*)(firmware*,int))(sig->ev_name))(fw,sig->offset);
4053     case 23:    return fw_string_process(fw, sig, match_strsig23, 1);
4054     case 24:    return fw_string_process(fw, sig, match_strsig24, 0);
4055     }
4056 
4057     return 0;
4058 }
4059 
4060 //------------------------------------------------------------------------------------------------------------
4061 
4062 // Matching functions
4063 
4064 // Search using new style matching only
4065 void find_str_sig_matches(firmware *fw, const char *curr_name)
4066 {
4067     int i;
4068 
4069     int found_ev = 0;
4070 
4071     count = 0;
4072 
4073     for (i = 0; string_sigs[i].ev_name != 0 && !found_ev; i++)
4074     {
4075         if (strcmp(curr_name, string_sigs[i].name) == 0)
4076         {
4077             if (find_strsig(fw, &string_sigs[i]))
4078             {
4079                 found_ev = 1;
4080                 break;
4081             }
4082         }
4083     }
4084 
4085     if (count > 1)
4086     {
4087         qsort(matches, count, sizeof(Match), (void*)match_compare);
4088     }
4089 
4090     if (count > 0)
4091     {
4092         save_sig(curr_name, matches->ptr);
4093     }
4094 }
4095 
4096 // Search using new style matching first
4097 // If not found used old style matching
4098 void find_matches(firmware *fw, const char *curr_name)
4099 {
4100     FuncSig *sig, *s;
4101     BufRange *n;
4102     uint32_t *p;
4103     int i, j;
4104     int fail, success;
4105 
4106     int found_ev = 0;
4107 
4108     count = 0;
4109 
4110     // Already found (eventproc)?
4111     i = find_saved_sig(curr_name);
4112     if (i >= 0)
4113     {
4114         if ((func_names[i].val != 0) && (func_names[i].flags & EV_MATCH) != 0)
4115         {
4116             fwAddMatch(fw,func_names[i].val,32,0,120);
4117             found_ev = 1;
4118         }
4119     }
4120 
4121 
4122     // Try and match using 'string' based signature matching first
4123     for (i = 0; string_sigs[i].ev_name != 0 && !found_ev; i++)
4124     {
4125         if (strcmp(curr_name, string_sigs[i].name) == 0)
4126         {
4127             if (find_strsig(fw, &string_sigs[i]))
4128             {
4129                 found_ev = 1;
4130                 break;
4131             }
4132         }
4133     }
4134 
4135     // If not found see if the name is in the old style instruction compare match table
4136     // Set start value for j in next section if found
4137     if (!found_ev)
4138     {
4139         found_ev = 1;
4140         for (j=0; func_list[j].name; j++)
4141         {
4142             if (strcmp(curr_name,func_list[j].name) == 0)
4143             {
4144                 found_ev = 0;
4145                 break;
4146             }
4147         }
4148     }
4149 
4150     // Not found so far, try instruction comparison matching
4151     while (!found_ev)
4152     {
4153         sig = func_list[j].sig;
4154 
4155         for (n = fw->br; n != 0; n = n->next)
4156         {
4157             for (p = n->p, i = 0; i < n->len; p++, i++)
4158             {
4159                 fail = 0;
4160                 success = 0;
4161                 for (s = sig; s->offs != 0xFFFFFFFF; s++)
4162                 {
4163                     if ((p[s->offs] & s->mask) != s->value)
4164                         fail++;
4165                     else
4166                         success++;
4167                 }
4168                 // If sig starts with STMFD and first instruction does not match ignore it
4169                 if (((p[sig->offs] & sig->mask) != sig->value) && (sig->offs == 0) && (sig->value == 0xe92d0000)) success = 0;
4170                 if (success > fail)
4171                 {
4172                     if (s->mask == 0xFFFFFFFE)
4173                     {
4174                         int end_branch = 0;
4175                         int idx = 0;
4176                         uint32_t *p1 = 0;
4177                         if ((fw->buf[n->off+i+s->value] & 0x0F000000) == 0x0A000000)   // B
4178                         {
4179                             idx = adr2idx(fw, followBranch2(fw, idx2adr(fw,n->off+i+s->value), 0xF0000001));
4180                             if ((idx >= 0) && (idx < fw->size))
4181                             {
4182                                 end_branch = 1;
4183                                 p1 = &fw->buf[idx];
4184                             }
4185                         }
4186                         int fail2 = 0;
4187                         int success2 = 0;
4188                         //fprintf(stderr,"\t%s %d %08x %08x %d %d\n",curr_name,idx,idx2adr(fw,idx),idx2adr(fw,i+n->off),success,fail);
4189                         s++;
4190                         for (; s->offs != 0xFFFFFFFF; s++)
4191                         {
4192                             if (!end_branch || (p1[s->offs] & s->mask) != s->value){
4193                                 fail2++;
4194                             } else {
4195                                 success2++;
4196                             }
4197                         }
4198                         if (fail2 == 0)
4199                         {
4200                             success = success + fail + success2;
4201                             fail = 0;
4202                         }
4203                         else
4204                         {
4205                             success = success + success2;
4206                             fail = fail + fail2;
4207                         }
4208                         //fprintf(stderr,"\t%s %d %08x %08x %d %d\n",curr_name,idx,idx2adr(fw,idx),idx2adr(fw,i+n->off),success,fail);
4209                     }
4210                 }
4211                 if (success > fail)
4212                 {
4213                     // Special case for drive space functions, see if there is a refernce to "Mounter.c" in the function
4214                     // Increase match % if so, increase fail count if not
4215                     if ((strcmp(curr_name, "GetDrive_ClusterSize") == 0) ||
4216                         (strcmp(curr_name, "GetDrive_FreeClusters") == 0) ||
4217                         (strcmp(curr_name, "GetDrive_TotalClusters") == 0))
4218                     {
4219                         int fnd = 0;
4220                         for (s = sig; s->offs != 0xFFFFFFFF; s++)
4221                         {
4222                             if (isLDR_PC_cond(fw,n->off+i+s->offs))
4223                             {
4224                                 int m = adr2idx(fw,LDR2val(fw,n->off+i+s->offs));
4225                                 if ((m >= 0) && (m < fw->size) && (strcmp((char*)(&fw->buf[m]),"Mounter.c") == 0))
4226                                 {
4227                                     fnd = 1;
4228                                 }
4229                             }
4230                             else if (isADR_PC_cond(fw,n->off+i+s->offs))
4231                             {
4232                                 int m = adr2idx(fw,ADR2adr(fw,n->off+i+s->offs));
4233                                 if ((m >= 0) && (m < fw->size) && (strcmp((char*)(&fw->buf[m]),"Mounter.c") == 0))
4234                                 {
4235                                     fnd = 1;
4236                                 }
4237                             }
4238                         }
4239                         if (fnd)
4240                             success++;
4241                         else
4242                             fail++;
4243                     }
4244                     fwAddMatch(fw,idx2adr(fw,i+n->off),success,fail,func_list[j].ver);
4245                     if (count >= MAX_MATCHES)
4246                     {
4247                         bprintf("// WARNING: too many matches for %s!\n", func_list[j].name);
4248                         break;
4249                     }
4250                 }
4251             }
4252         }
4253 
4254         // same name, so we have another version of the same function
4255         if ((func_list[j+1].name == NULL) || (strcmp(curr_name, func_list[j+1].name) != 0))
4256         {
4257             found_ev = 1;
4258             break;
4259         }
4260         j++;
4261     }
4262 
4263     if (count > 1)
4264     {
4265         qsort(matches, count, sizeof(Match), (void*)match_compare);
4266     }
4267 
4268     if (count > 0)
4269     {
4270         save_sig(curr_name, matches->ptr);
4271     }
4272 }
4273 
4274 // Output match results for function
4275 void print_results(firmware *fw, const char *curr_name, int k)
4276 {
4277     int i;
4278     int err = 0;
4279     char line[500] = "";
4280 
4281     if (func_names[k].flags & DONT_EXPORT) return;
4282 
4283     // find best match and report results
4284     osig* ostub2 = find_sig(fw->sv->stubs,curr_name);
4285 
4286     if ((count == 0)
4287         || (matches->fail > 0)
4288         || (ostub2 && (matches->ptr != ostub2->val))
4289        )
4290     {
4291         if (!ostub2 || (ostub2->type != TYPE_IGNORE))
4292             err = 1;
4293         func_names[k].flags |= BAD_MATCH;
4294     }
4295     else
4296     {
4297         if (func_names[k].flags & UNUSED) return;
4298     }
4299 
4300     // write to header (if error) or body buffer (no error)
4301     out_hdr = err;
4302 
4303     char *macro = "NHSTUB";
4304     if (strncmp(curr_name,"task_",5) == 0 ||
4305         strncmp(curr_name,"hook_",5) == 0) macro = "   DEF";
4306 
4307     if (count == 0)
4308     {
4309         if (func_names[k].flags & OPTIONAL) return;
4310         char fmt[51] = "";
4311         sprintf(fmt, "// ERROR: %%s is not found. %%%ds//--- --- ", (int)(34-strlen(curr_name)));
4312         sprintf(line+strlen(line), fmt, curr_name, "");
4313     }
4314     else
4315     {
4316         if (ostub2 || (func_names[k].flags & UNUSED))
4317             sprintf(line+strlen(line),"//%s(%-37s,0x%08x) //%3d ", macro, curr_name, matches->ptr, matches->sig);
4318         else
4319             sprintf(line+strlen(line),"%s(%-39s,0x%08x) //%3d ", macro, curr_name, matches->ptr, matches->sig);
4320 
4321         if (matches->fail > 0)
4322             sprintf(line+strlen(line),"%2d%% ", matches->success*100/(matches->success+matches->fail));
4323         else
4324             sprintf(line+strlen(line),"    ");
4325     }
4326 
4327     if (ostub2)
4328     {
4329         if (ostub2->type == TYPE_IGNORE)
4330             sprintf(line+strlen(line),"       Overridden");
4331         else if ((count > 0) && (matches->ptr == ostub2->val))
4332             sprintf(line+strlen(line),"       == 0x%08x    ",ostub2->val);
4333         else
4334             sprintf(line+strlen(line),"   *** != 0x%08x    ",ostub2->val);
4335     }
4336     else
4337         sprintf(line+strlen(line),"                        ");
4338 
4339     for (i=strlen(line)-1; i>=0 && line[i]==' '; i--) line[i] = 0;
4340     bprintf("%s\n",line);
4341 
4342     for (i=1;i<count && matches[i].fail==matches[0].fail;i++)
4343     {
4344         if (matches[i].ptr != matches->ptr)
4345         {
4346             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);
4347         }
4348     }
4349 }
4350 
4351 //------------------------------------------------------------------------------------------------------------
4352 
4353 typedef struct
4354 {
4355     uint16_t mode;
4356     char *nm;
4357 } ModeMapName;
4358 
4359 ModeMapName mmnames[] = {
4360     { 32768,"MODE_AUTO" },
4361     { 32769,"MODE_M" },
4362     { 32770,"MODE_AV" },
4363     { 32771,"MODE_TV" },
4364     { 32772,"MODE_P" },
4365 
4366     { 65535,"" }
4367 };
4368 
4369 char* mode_name(uint16_t v)
4370 {
4371     int i;
4372     for (i=0; mmnames[i].mode != 65535; i++)
4373     {
4374         if (mmnames[i].mode == v)
4375             return mmnames[i].nm;
4376     }
4377 
4378     return "";
4379 }
4380 
4381 void output_modemap(firmware *fw, int k)
4382 {
4383     int cnt = 0;
4384 
4385     if (isLDR_PC(fw,k))
4386     {
4387         k = adr2idx(fw,LDR2val(fw,k));
4388         bprintf("%08x\n",idx2adr(fw,k));
4389         uint16_t *p = (uint16_t*)(&fw->buf[k]);
4390         k = 0;
4391         while ((*p != 0xFFFF) && (k < 50))
4392         {
4393             if (((fw->dryos_ver < 47) && ((*p < 8000) || (*p > 8999))) || ((fw->dryos_ver >= 47) && ((*p < 4000) || (*p > 4999))))
4394             {
4395                 osig *m = find_sig_val(fw->sv->modemap, *p);
4396                 if (!m)
4397                 {
4398                     char *s = mode_name(*p);
4399                     bprintf("// Mode %5d in firmware but not in current modemap",*p);
4400                     if (strcmp(s,"") != 0)
4401                         bprintf(" (%s)",s);
4402                     bprintf("\n");
4403                     cnt++;
4404                 }
4405                 else
4406                 {
4407                     m->pct = 100;
4408                 }
4409             }
4410             p++;
4411             k++;
4412         }
4413     }
4414     osig *m = fw->sv->modemap;
4415     while (m)
4416     {
4417         if (m->pct != 100)    // not matched above?
4418         {
4419             bprintf("// Current modemap entry not found in firmware - %-24s %5d\n",m->nm,m->val);
4420             cnt++;
4421         }
4422         m = m->nxt;
4423     }
4424     if (cnt == 0)
4425     {
4426         bprintf("// No problems found with modemap table.\n");
4427     }
4428 }
4429 
4430 int match_modelist(firmware *fw, int k, uint32_t fadr, __attribute__ ((unused))uint32_t v2)
4431 {
4432     if (isBX_LR(fw,k) && (fw->buf[k+4] == fadr))
4433     {
4434         fadr = fwval(fw,k+1);
4435         int k1;
4436         for (k1=k-1; k1>k-20; k1--)
4437         {
4438             if (isLDR_PC(fw,k1) && (LDR2val(fw,k1) == fadr))
4439             {
4440                 bprintf("// Firmware modemap table found @%08x -> ",idx2adr(fw,k1));
4441                 output_modemap(fw,k1);
4442                 return 1;
4443             }
4444         }
4445     }
4446 
4447     return 0;
4448 }
4449 
4450 static uint32_t FlashParamsTable_address = 0;
4451 
4452 int match_FlashParamsTable2(firmware *fw, int k, uint32_t v1, __attribute__ ((unused))uint32_t v2)
4453 {
4454     if (fw->buf[k] == v1)
4455     {
4456         FlashParamsTable_address = idx2adr(fw,k);
4457         return 1;
4458     }
4459     return 0;
4460 }
4461 
4462 int match_FlashParamsTable(firmware *fw, int k, __attribute__ ((unused))uint32_t v1, __attribute__ ((unused))uint32_t v2)
4463 {
4464     if ((fw->buf[k] > fw->base) && (fw->buf[k+1] == 0x00010000) && (fw->buf[k+2] == 0xFFFF0002))
4465     {
4466         if (search_fw(fw, match_FlashParamsTable2, idx2adr(fw,k), 0, 1))
4467             return 1;
4468     }
4469     return 0;
4470 }
4471 
4472 void find_modemap(firmware *fw)
4473 {
4474     out_hdr = 1;
4475 
4476     // Find 'FlashParamsTable'
4477     search_fw(fw, match_FlashParamsTable, 0, 0, 1);
4478     // Find 'modelist'
4479     if (FlashParamsTable_address != 0)
4480     {
4481         add_blankline();
4482         bprintf("// Check of modemap from 'platform/CAMERA/shooting.c':\n");
4483         search_fw(fw, match_modelist, FlashParamsTable_address, 0, 5);
4484     }
4485 }
4486 
4487 //------------------------------------------------------------------------------------------------------------
4488 
4489 int match_CAM_UNCACHED_BIT(firmware *fw, int k, __attribute__ ((unused))int v)
4490 {
4491     if ((fw->buf[k] & 0x0FFFF000) == 0x03C00000)    // BIC
4492     {
4493         fw->uncached_adr = ALUop2(fw,k);
4494         fw->uncached_adr_idx = k;
4495     }
4496 
4497     return 0;
4498 }
4499 
4500 int find_DebugAssert_argcount(firmware *fw)
4501 {
4502     int s1 = find_str_ref(fw, "CameraLog.c");
4503     if (s1 < 0)
4504         return 0;
4505     int k = isADR_PC_cond(fw, s1);
4506     if (!k)
4507         return 0;
4508     k = fwRd(fw, s1);
4509     if (k > 0)
4510         bprintf("//#define CAM_3ARG_DebugAssert 1\n");
4511     return 1;
4512 }
4513 
4514 // Search for things that go in 'platform_camera.h'
4515 void find_platform_vals(firmware *fw)
4516 {
4517     int k,k1;
4518 
4519     out_hdr = 1;
4520     add_blankline();
4521 
4522     bprintf("// Values below go in 'platform_camera.h':\n");
4523     bprintf("//#define CAM_DRYOS         1\n");
4524     if (fw->dryos_ver >= 39)
4525         bprintf("//#define CAM_DRYOS_2_3_R39 1 // Defined for cameras with DryOS version R39 or higher\n");
4526     if (fw->dryos_ver >= 47)
4527         bprintf("//#define CAM_DRYOS_2_3_R47 1 // Defined for cameras with DryOS version R47 or higher\n");
4528     if (fw->dryos_ver >= 59)
4529         bprintf("//#define CAM_DRYOS_2_3_R59 1 // Defined for cameras with DryOS version R59 or higher\n");
4530 
4531     // Find 'RAW' image size
4532     uint32_t raw_width = 0;
4533     uint32_t raw_height = 0;
4534     uint32_t kw=0, kh=0;
4535 
4536     k = find_str_ref(fw, "\r[%ld] AdjDrvType[%02ld] -> DrvType[%02");
4537     if (k >= 0)
4538     {
4539         // Width
4540         for (k1 = k-1; k1 >= k-20; k1--)
4541         {
4542             if ((fw->buf[k1] & 0x0FFF0FFF) == 0x058D0034)           // STRxx Rn, [SP,#0x34]
4543             {
4544                 if ((fw->buf[k1-1] & 0x0FFF0000) == 0x03A00000)     // MOVxx Rn, #YYY
4545                 {
4546                     raw_width = ALUop2(fw, k1-1);
4547                     kw = k1-1;
4548                 }
4549                 else if ((fw->buf[k1-2] & 0x0FFF0000) == 0x03A00000)// MOVxx Rn, #YYY
4550                 {
4551                     raw_width = ALUop2(fw, k1-2);
4552                     kw = k1-2;
4553                 }
4554                 else if (isLDR_PC_cond(fw,k1-1))
4555                 {
4556                     raw_width = LDR2val(fw,k1-1);
4557                     kw = k1-1;
4558                 }
4559                 else if (isLDR_PC_cond(fw,k1-2))
4560                 {
4561                     raw_width = LDR2val(fw,k1-2);
4562                     kw = k1-2;
4563                 }
4564             }
4565         }
4566         // Height
4567         for (k1 = k-1; k1 >= k-20; k1--)
4568         {
4569             if ((fw->buf[k1] & 0x0FFF0FFF) == 0x058D0030)           // STRxx Rn, [SP,#0x30]
4570             {
4571                 if ((fw->buf[k1-1] & 0x0FFF0000) == 0x03A00000)     // MOVxx Rn, #YYY
4572                 {
4573                     raw_height = ALUop2(fw, k1-1);
4574                     kh = k1-1;
4575                 }
4576                 else if ((fw->buf[k1-2] & 0x0FFF0000) == 0x03A00000)// MOVxx Rn, #YYY
4577                 {
4578                     raw_height = ALUop2(fw, k1-2);
4579                     kh = k1-2;
4580                 }
4581                 else if (isLDR_PC_cond(fw,k1-1))
4582                 {
4583                     raw_height = LDR2val(fw,k1-1);
4584                     kh = k1-1;
4585                 }
4586                 else if (isLDR_PC_cond(fw,k1-2))
4587                 {
4588                     raw_height = LDR2val(fw,k1-2);
4589                     kh = k1-2;
4590                 }
4591                 if ((fw->buf[k1-1] & 0x0FFF0000) == 0x02400000)     // SUBxx Rn, #YYY
4592                 {
4593                     raw_height = raw_width - ALUop2(fw, k1-1);
4594                     kh = k1-1;
4595                 }
4596             }
4597         }
4598     }
4599 
4600     if ((raw_width == 0) && (raw_height == 0))
4601     {
4602         k = find_str_ref(fw, " CrwAddress %lx, CrwSize H %ld V %ld\r");
4603         if (k >= 0)
4604         {
4605             // Width
4606             for (k1=k-1; k1>=k-5; k1--)
4607             {
4608                 if ((fw->buf[k1] & 0xFFFFF000) == 0xE3A02000)       // MOV R2, #nnn
4609                 {
4610                     raw_width = ALUop2(fw,k1);
4611                     kw = k1;
4612                 }
4613                 else
4614                 if (isLDR_PC(fw,k1) && ((fw->buf[k1]& 0x0000F000) == 0x00002000))   // LDR R2, =nnn
4615                 {
4616                     raw_width = LDR2val(fw,k1);
4617                     kw = k1;
4618                 }
4619             }
4620             // Height
4621             for (k1=k-1; k1>=k-5; k1--)
4622             {
4623                 if ((fw->buf[k1] & 0xFFFFF000) == 0xE3A03000)       // MOV R3, #nnn
4624                 {
4625                     raw_height = ALUop2(fw,k1);
4626                     kh = k1;
4627                 }
4628                 else
4629                 if (isLDR_PC(fw,k1) && ((fw->buf[k1]& 0x0000F000) == 0x00003000))   // LDR R3, =nnn
4630                 {
4631                     raw_height = LDR2val(fw,k1);
4632                     kh = k1;
4633                 }
4634                 else
4635                 if ((fw->buf[k1] & 0xFFFFF000) == 0xE2423000)       // SUB R3, R2, #nnn
4636                 {
4637                     raw_height = raw_width - ALUop2(fw,k1);
4638                     kh = k1;
4639                 }
4640             }
4641         }
4642     }
4643 
4644     if (raw_width != 0)
4645     {
4646         bprintf("//#define CAM_RAW_ROWPIX    %d // Found @0x%08x\n",raw_width,idx2adr(fw,kw));
4647     }
4648     else
4649     {
4650         bprintf("//#define CAM_RAW_ROWPIX    *** Not Found ***\n");
4651     }
4652     if (raw_height != 0)
4653     {
4654         bprintf("//#define CAM_RAW_ROWS      %d // Found @0x%08x\n",raw_height,idx2adr(fw,kh));
4655     }
4656     else
4657     {
4658         bprintf("//#define CAM_RAW_ROWS      *** Not Found ***\n");
4659     }
4660 
4661     // Find 'CAM_UNCACHED_BIT'
4662     if (fw->uncached_adr_idx != 0)
4663     {
4664         bprintf("//#undef  CAM_UNCACHED_BIT\n");
4665         bprintf("//#define CAM_UNCACHED_BIT  0x%08x // Found @0x%08x\n",fw->uncached_adr,idx2adr(fw,fw->uncached_adr_idx));
4666     }
4667 
4668     // Look for CAM_DATE_FOLDER_NAMING value
4669     k = get_saved_sig(fw,"GetImageFolder");
4670     if (k >= 0)
4671     {
4672         uint32_t fadr = func_names[k].val;
4673         int s = adr2idx(fw,fadr);
4674         int e = find_inst(fw, isLDMFD_PC, s+1, 160);
4675         for (k1=s+1; k1<s+16; k1++)
4676         {
4677             if (isMOV(fw,k1) && (fwRnMOV(fw,k1) == 2))
4678             {
4679                 int r1 = fwRd(fw,k1);
4680                 int k2;
4681                 for (k2=e-32; k2<e; k2++)
4682                 {
4683                     int b = 0;
4684                     if (isMOV(fw,k2) && isBL(fw,k2+1) && (fwRnMOV(fw,k2) == r1))
4685                         b = 1;
4686                     else if (isMOV(fw,k2) && isBL(fw,k2+7) && (fwRnMOV(fw,k2) == r1))
4687                         b = 7;
4688                     if (b != 0)
4689                     {
4690                         int r2 = fwRd(fw,k2);
4691                         fadr = followBranch2(fw,idx2adr(fw,k2+b),0x01000001);
4692                         k = adr2idx(fw,fadr);
4693                         int k3;
4694                         for (k3=k; k3<k+8; k3++)
4695                         {
4696                             if (isCMP(fw,k3) && (fwRn(fw,k3) == r2))
4697                             {
4698                                 int val = ALUop2(fw,k3);
4699                                 bprintf("//#define CAM_DATE_FOLDER_NAMING 0x%03x // Found @0x%08x (pass as 3rd param to GetImageFolder)\n",val,idx2adr(fw,k3));
4700                             }
4701                         }
4702                     }
4703                 }
4704             }
4705         }
4706     }
4707 
4708     // Find 'PARAM_CAMERA_NAME'
4709     if (FlashParamsTable_address != 0)
4710     {
4711         k1 = adr2idx(fw,FlashParamsTable_address);
4712         for (k=k1; k<k1+20; k++)
4713         {
4714             uint32_t fadr = fwval(fw,k);
4715             int k2 = adr2idx(fw,fadr);
4716             if (idx_valid(fw,k2))
4717             {
4718                 uint32_t sadr = fwval(fw,k2);
4719                 k2 = adr2idx(fw,sadr);
4720                 if (idx_valid(fw,k2))
4721                 {
4722                     char *s = adr2ptr(fw,sadr);
4723                     if (((fw->cam != 0) && (strcmp(s,fw->cam) == 0)) || (strcmp(s,"Unknown") == 0))
4724                     {
4725                         bprintf("//#define PARAM_CAMERA_NAME %d // Found @0x%08x\n",k-k1,fadr);
4726                         break;
4727                     }
4728                 }
4729             }
4730         }
4731     }
4732 
4733     find_DebugAssert_argcount(fw);
4734 
4735     if (cam_has_wifi) {
4736         bprintf("//#define CAM_HAS_WIFI 1 // Firmware has wifi support (only define if camera has hardware)\n");
4737     }
4738 
4739     k = get_saved_sig(fw,"task_FileWrite");
4740     if (k >= 0)
4741     {
4742         uint32_t fadr = func_names[k].val;
4743         k1 = adr2idx(fw, fadr);
4744         for (k=1; k<32; k++)
4745         {
4746             if ((fwval(fw, k1+k) & 0x0fffff00) == 0x008ff100) // add[cond] pc, pc, rx, lsl#2
4747             {
4748                 for (k++;isB(fw,k1+k) && idxFollowBranch(fw,k1+k,1) != idxFollowBranch(fw,k1+k-1,1);k++);
4749                 int c = 1;
4750                 for (;isB(fw,k1+k) && idxFollowBranch(fw,k1+k,1) == idxFollowBranch(fw,k1+k-1,1);k++,c++);
4751                 bprintf("\n// Below goes in 'filewrite.c' or 'platform_camera.h':\n");
4752                 bprintf("//#define MAX_CHUNKS_FOR_FWT %d // Found @0x%08x\n",c,idx2adr(fw,k+k1));
4753                 break;
4754             }
4755         }
4756     }
4757 }
4758 
4759 //------------------------------------------------------------------------------------------------------------
4760 
4761 uint32_t find_viewport_address(firmware *fw, int *kout)
4762 {
4763     int k, k1;
4764 
4765     // find viewwport address for 'vid_get_viewport_fb'
4766     k = find_str_ref(fw, "VRAM Address  : %p\r");
4767     if (k >= 0)
4768     {
4769         for (k1=k-1; k1>k-8; k1--)
4770         {
4771             if (isLDR(fw,k1) && isLDR(fw,k1+1))
4772             {
4773                 uint32_t v1 = LDR2val(fw,k1);
4774                 uint32_t v2 = LDR2val(fw,k1+1);
4775                 if (v2 > v1) v1 = v2;
4776                 *kout = k1;
4777                 return v1;
4778             }
4779         }
4780     }
4781 
4782     *kout = -1;
4783     return 0;
4784 }
4785 
4786 int match_vid_get_bitmap_fb(firmware *fw, int k, __attribute__ ((unused))int v)
4787 {
4788     if (isBL(fw,k-1) && // BL
4789         isLDR_PC(fw,k))
4790     {
4791         uint32_t v1 = LDR2val(fw,k);
4792         bprintf("//void *vid_get_bitmap_fb()        { return (void*)0x%08x; }             // Found @0x%08x\n",v1,idx2adr(fw,k));
4793         return 1;
4794     }
4795     else
4796     if (isBL(fw,k-1) && // BL
4797         (isLDR_PC(fw,k+1)))
4798     {
4799         uint32_t v1 = LDR2val(fw,k+1);
4800         bprintf("//void *vid_get_bitmap_fb()        { return (void*)0x%08x; }             // Found @0x%08x\n",v1,idx2adr(fw,k));
4801         return 1;
4802     }
4803 
4804     return 0;
4805 }
4806 
4807 int match_get_flash_params_count(firmware *fw, int k, __attribute__ ((unused))int v)
4808 {
4809     if ((fw->buf[k] & 0xFFF00FFF) == 0xE3C00901)    // BIC Rn, Rn, #0x4000
4810     {
4811         uint32_t r = fw->buf[k] & 0x000F0000;       // Register
4812         if (((fw->buf[k+1] & 0xFFF00000) == 0xE3500000) && ((fw->buf[k+1] & 0x000F0000) == r))  // CMP, Rn #val
4813         {
4814             bprintf("//int get_flash_params_count(void) { return 0x%02x; }                          // Found @0x%08x\n",fw->buf[k+1]&0xFFF,idx2adr(fw,k+1));
4815             return 1;
4816         }
4817     }
4818 
4819     return 0;
4820 }
4821 
4822 // based on match_get_flash_params_count
4823 int match_uiprop_count(firmware *fw, int k, __attribute__ ((unused))int v)
4824 {
4825     if ((fw->buf[k] & 0xFFF00FFF) == 0xe3c00902)    // BIC Rn, Rn, #0x8000
4826     {
4827         uint32_t r = fw->buf[k] & 0x000F0000;       // Register
4828         if (((fw->buf[k+1] & 0xFFF00000) == 0xE3500000) && ((fw->buf[k+1] & 0x000F0000) == r))  // CMP, Rn #val
4829         {
4830             char *name = "uiprop_count";
4831             uint32_t fadr = fw->buf[k+1]&0xFFF;
4832             osig *o = find_sig(fw->sv->stubs_min,name);
4833             if (o)
4834             {
4835                 bprintf("//DEF_CONST(%-34s,0x%08x) // Found @0x%08x",name,fadr,idx2adr(fw,k+1));
4836                 if (fadr != o->val)
4837                 {
4838                     bprintf(", ** != ** stubs_min = 0x%08x (%s)",o->val,o->sval);
4839                 }
4840                 else
4841                 {
4842                     bprintf(",          stubs_min = 0x%08x (%s)",o->val,o->sval);
4843                 }
4844             }
4845             else
4846             {
4847                 bprintf("DEF_CONST(%-34s,0x%08x) // Found @0x%08x",name,fadr,idx2adr(fw,k+1));
4848             }
4849             bprintf("\n");
4850             return 1;
4851         }
4852     }
4853 
4854     return 0;
4855 }
4856 
4857 int match_imager_active(firmware *fw, int k, __attribute__ ((unused))int v)
4858 {
4859     int gotit = 0;
4860     int reg = -1;
4861     int o = 0;
4862     uint32_t adr,where;
4863     if (isLDMFD_PC(fw,k))
4864     {
4865         int k1 = find_inst_rev(fw, isBL, k-1, 10);
4866         if (k1 == -1)
4867             return 0;
4868         uint32_t a;
4869         int k2 = k1 - 8;
4870         for (k1=k1-1;k1>=k2;k1--)
4871         {
4872             if (isLDR(fw,k1) || isADR(fw,k1))
4873             {
4874                 if (isADR(fw,k1))
4875                 {
4876                     a = ADR2adr(fw, k1);
4877                 }
4878                 else
4879                 {
4880                     a = LDR2val(fw, k1);
4881                 }
4882                 if ((a>fw->base) && ((a&3) == 0))
4883                 {
4884                     int k3 = adr2idx(fw, a);
4885                     if (isSTMFD_LR(fw,k3))
4886                     {
4887                         k3 = find_inst(fw, isBLX, k3+1, 6);
4888                         if (k3 != -1)
4889                         {
4890                             int k4;
4891                             for(k4=5; k4>0; k4--)
4892                             {
4893                                 if (isSTR_cond(fw,k3+k4))
4894                                 {
4895                                     reg = fwRn(fw,k3+k4);
4896                                     o = fwval(fw,k3+k4) & 0xff; // offset, should be around 4
4897                                     where = idx2adr(fw,k3+k4);
4898                                 }
4899                                 if (reg>=0 && isLDR_cond(fw,k3+k4) && fwRd(fw,k3+k4)==reg)
4900                                 {
4901                                     adr = LDR2val(fw,k3+k4);
4902                                     if (adr < fw->memisostart)
4903                                     {
4904                                         gotit = 1;
4905                                         break;
4906                                     }
4907                                 }
4908                             }
4909                             if (gotit)
4910                                 break;
4911                         }
4912                     }
4913                 }
4914             }
4915         }
4916     }
4917     if (gotit)
4918     {
4919         bprintf("DEF(%-40s,0x%08x) // Found @0x%08x (0x%x + %i)\n","imager_active",adr+o,where,adr,o);
4920         return 1;
4921     }
4922     return 0;
4923 }
4924 
4925 // Search for things that go in 'lib.c'
4926 void find_lib_vals(firmware *fw)
4927 {
4928     int k,k1;
4929 
4930     out_hdr = 1;
4931     add_blankline();
4932 
4933     bprintf("// Values below go in 'lib.c':\n");
4934 
4935     // Find 'vid_get_bitmap_fb'
4936     search_saved_sig(fw, "DispCon_ShowBitmapColorBar", match_vid_get_bitmap_fb, 0, 1, 30);
4937 
4938     // find 'vid_get_viewport_fb'
4939     uint32_t v = find_viewport_address(fw,&k);
4940     if (k >= 0)
4941     {
4942         bprintf("//void *vid_get_viewport_fb()      { return (void*)0x%08x; }             // Found @0x%08x\n",v,idx2adr(fw,k));
4943     }
4944 
4945     // find 'vid_get_viewport_fb_d'
4946     static int fbd[3][3] =
4947     {
4948         { -2, -3,  1 },
4949         {  1,  3,  4 },
4950         { -1, -2,  1 },
4951     };
4952     int sadr = find_str(fw, "ImagePlayer.c");
4953     k = find_nxt_str_ref(fw, sadr, -1);
4954     int found = 0;
4955     while ((k >= 0) && !found)
4956     {
4957         int f;
4958         for (f=0; f<3 && !found; f++)
4959         {
4960             if (isLDR(fw,k+fbd[f][0]) && isLDR(fw,k+fbd[f][1]) && isLDR(fw,k+fbd[f][2]))
4961             {
4962                 uint32_t reg = fw->buf[k+fbd[f][2]] & 0x000F0000;    // Index register used
4963                 int ka = 0;
4964                 if (((fw->buf[k+fbd[f][0]] & 0x0000F000) << 4) == reg)      { ka = k+fbd[f][0]; }
4965                 else if (((fw->buf[k+fbd[f][1]] & 0x0000F000) << 4) == reg) { ka = k+fbd[f][1]; }
4966                 if (ka > 0)
4967                 {
4968                     uint32_t adr = LDR2val(fw,ka);
4969                     for (k1=k+2; k1<k+20; k1++)
4970                     {
4971                         if (isSTR(fw,k1) && ((fw->buf[k1] & 0x000F0000) == reg))
4972                         {
4973                             uint32_t ofst = fw->buf[k1] & 0x00000FFF;
4974                             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));
4975                             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));
4976                             found = 1;
4977                             break;
4978                         }
4979                     }
4980                 }
4981             }
4982         }
4983         k = find_nxt_str_ref(fw, sadr, k);
4984     }
4985 
4986     // find 'camera_jpeg_count_str'
4987     k = find_str_ref(fw, "9999");
4988     if (k >= 0)
4989     {
4990         if (isLDR(fw,k-1) && isBL(fw,k+1))
4991         {
4992             uint32_t v1 = LDR2val(fw,k-1);
4993             bprintf("DEF(%-40s,0x%08x) // Found @0x%08x\n","jpeg_count_str",v1,idx2adr(fw,k-1));
4994             bprintf("//char *camera_jpeg_count_str()    { return (char*)0x%08x; }             // Found @0x%08x\n",v1,idx2adr(fw,k-1));
4995         }
4996     }
4997 
4998 //    // find 'hook_raw_size'
4999 //    k = find_str_ref(fw, "CRAW BUFF SIZE  %p");
5000 //    if (k >= 0)
5001 //    {
5002 //        if (isLDR(fw,k-1))
5003 //        {
5004 //            uint32_t craw_bufsize = LDR2val(fw,k-1);
5005 //            bprintf("//long hook_raw_size()             { return 0x%08x; }                    // Found @0x%08x\n",craw_bufsize,idx2adr(fw,k-1));
5006 //        }
5007 //    }
5008 
5009     // Find value for 'get_flash_params_count'
5010     search_saved_sig(fw, "GetParameterData", match_get_flash_params_count, 0, 0, 30);
5011 }
5012 
5013 //------------------------------------------------------------------------------------------------------------
5014 
5015 void print_stubs_min(firmware *fw, const char *name, uint32_t fadr, uint32_t atadr)
5016 {
5017     osig *o = find_sig(fw->sv->stubs_min,name);
5018     if (o)
5019     {
5020         bprintf("//DEF(%-40s,0x%08x) // Found @0x%08x",name,fadr,atadr);
5021         if (fadr != o->val)
5022         {
5023             bprintf(", ** != ** stubs_min = 0x%08x (%s)",o->val,o->sval);
5024         }
5025         else
5026         {
5027             bprintf(",          stubs_min = 0x%08x (%s)",o->val,o->sval);
5028         }
5029     }
5030     else
5031     {
5032         bprintf("DEF(%-40s,0x%08x) // Found @0x%08x",name,fadr,atadr);
5033     }
5034     bprintf("\n");
5035 }
5036 
5037 uint32_t exm_typ_tbl=0, exm_typ_cnt=0;
5038 int print_exmem_types(firmware *fw)
5039 {
5040     if (exm_typ_tbl==0 || exm_typ_cnt==0)
5041         return 1;
5042     bprintf("// EXMEM types:\n");
5043     int ii = adr2idx(fw, exm_typ_tbl);
5044     uint32_t n;
5045     for (n=0; n<exm_typ_cnt; n++)
5046     {
5047         bprintf("// %s %i\n",adr2ptr(fw, fwval(fw,ii+n)),n);
5048     }
5049     bprintf("\n");
5050     return 0;
5051 }
5052 
5053 int find_exmem_alloc_table(firmware *fw)
5054 {
5055     int i = get_saved_sig(fw,"ExMem.View_FW"); // s5 and earlier don't have this
5056     if (i < 0)
5057     {
5058         i = get_saved_sig(fw,"exmem_assert"); // s5
5059     }
5060     if (i < 0)
5061     {
5062         return 0;
5063     }
5064     i = adr2idx(fw, func_names[i].val);
5065     uint32_t u, us;
5066     uint32_t exm_typ_tbl_orig = 0;
5067     int n;
5068     us = 0;
5069     for (n=1; n<16; n++)
5070     {
5071         if ( ((fwval(fw,i+n)&0xffff0000)==0xe59f0000) ) // ldr rx, [pc, #imm]
5072         {
5073             u = LDR2val(fw, i+n);
5074             if (u>fw->data_start && u<fw->data_start+fw->data_len*4 && (fwRd(fw,i+n)>3))
5075             {
5076                 exm_typ_tbl_orig = u;
5077                 u = u - fw->data_start + fw->data_init_start;
5078                 break;
5079             }
5080             else if (us==0 && u>fw->base && u<fw->base+fw->size*4-4 && (u&3)==0)
5081             {
5082                 us = u;
5083             }
5084         }
5085         u = 0;
5086     }
5087     if (!u && us)
5088     {
5089         u = us;
5090         exm_typ_tbl_orig = u;
5091     }
5092     if (u)
5093     {
5094         exm_typ_tbl = u;
5095         int ii = adr2idx(fw, exm_typ_tbl);
5096         char* extyp;
5097         for (n=0; n<32; n++)
5098         {
5099             if ( (fwval(fw,ii+n)!=0) && isASCIIstring(fw, fwval(fw,ii+n)) )
5100             {
5101                 extyp = adr2ptr(fw, fwval(fw,ii+n));
5102                 if ( strncmp(extyp,"EXMEM",5)==0 )
5103                 {
5104                     exm_typ_cnt++;
5105                 }
5106             }
5107             else
5108             {
5109                 break;
5110             }
5111         }
5112     }
5113 
5114     for (n=1; n<42; n++)
5115     {
5116         if ( ((fwval(fw,i+n)&0xffff0000)==0xe59f0000) ) // ldr rx, [pc, #imm]
5117         {
5118             u = LDR2val(fw, i+n);
5119             if (u>fw->data_start+fw->data_len*4 && u<fw->memisostart && (fwRd(fw,i+n)>3))
5120             {
5121                 break;
5122             }
5123         }
5124         u = 0;
5125     }
5126     if (u)
5127     {
5128         print_stubs_min(fw,"exmem_alloc_table",u,idx2adr(fw,i+n));
5129     }
5130     if (exm_typ_tbl)
5131     {
5132         print_stubs_min(fw,"exmem_types_table",exm_typ_tbl,exm_typ_tbl_orig);
5133     }
5134     if (exm_typ_cnt)
5135     {
5136         bprintf("DEF_CONST(%-34s,0x%08x)\n","exmem_type_count",exm_typ_cnt);
5137     }
5138     return 0;
5139 }
5140 
5141 int match_levent_table(firmware *fw, int k, __attribute__ ((unused))uint32_t v1, __attribute__ ((unused))uint32_t v2)
5142 {
5143     if ((fw->buf[k] > fw->base) && (fw->buf[k+1] == 0x00000800) && (fw->buf[k+2] == 0x00000002))
5144     {
5145         print_stubs_min(fw,"levent_table",idx2adr(fw,k),idx2adr(fw,k));
5146 #ifdef PRINT_LEVENT_TABLE
5147         uint32_t levent_tbl = idx2adr(fw,k);
5148         void write_levent_table_dump(firmware*, uint32_t);
5149         write_levent_table_dump(fw, levent_tbl);
5150 #endif
5151     }
5152     return 0;
5153 }
5154 
5155 int match_movie_status(firmware *fw, int k, __attribute__ ((unused))uint32_t v1, __attribute__ ((unused))uint32_t v2)
5156 {
5157     if (isLDR_PC(fw, k) &&                              // LDR R0, =base
5158         ((fw->buf[k+1] & 0xFE0F0000) == 0xE20F0000) &&  // ADR R1, =sub
5159         isSTR(fw, k+2) &&                               // STR R1, [R0,N]
5160         (fw->buf[k+3] == 0xE3A01003) &&                 // MOV R1, 3
5161         isSTR(fw, k+4) &&                               // STR R1, [R0,ofst]
5162         (LDR2val(fw,k) < fw->base))
5163     {
5164         uint32_t base = LDR2val(fw,k);
5165         uint32_t ofst = fw->buf[k+4] & 0x00000FFF;
5166         print_stubs_min(fw,"movie_status",base+ofst,idx2adr(fw,k));
5167         return 1;
5168     }
5169     else
5170     if (isLDR_PC(fw, k) &&                              // LDR R1, =sub
5171         isLDR_PC(fw, k+1) &&                            // LDR R0, =base
5172         isSTR(fw, k+2) &&                               // STR R1, [R0,N]
5173         (fw->buf[k+3] == 0xE3A01003) &&                 // MOV R1, 3
5174         isSTR(fw, k+4) &&                               // STR R1, [R0,ofst]
5175         (LDR2val(fw,k+1) < fw->base))
5176     {
5177         uint32_t base = LDR2val(fw,k+1);
5178         uint32_t ofst = fw->buf[k+4] & 0x00000FFF;
5179         print_stubs_min(fw,"movie_status",base+ofst,idx2adr(fw,k));
5180         return 1;
5181     }
5182     else
5183     if (isLDR_PC(fw, k) &&                                      // LDR Rx, =base
5184         isLDR(fw, k+1) && (fwRd(fw,k) == fwRn(fw,k+1)) &&       // LDR R0, [Rx, ...]
5185         isCMP(fw, k+2) && (fwRd(fw,k+2) == fwRd(fw,k+1)) &&     // CMP R0, #...
5186         (fwval(fw,k+3) == 0x03A00005) &&
5187         isSTR_cond(fw, k+4) && (fwRn(fw,k+4) == fwRd(fw,k)) &&  // STRxx R0, [Rx,ofst]
5188         (LDR2val(fw,k) < fw->base))
5189     {
5190         uint32_t base = LDR2val(fw,k);
5191         uint32_t ofst = fwOp2(fw,k+4);
5192         print_stubs_min(fw,"movie_status",base+ofst,idx2adr(fw,k));
5193         return 1;
5194     }
5195     return 0;
5196 }
5197 
5198 int match_full_screen_refresh(firmware *fw, int k, __attribute__ ((unused))uint32_t v1, __attribute__ ((unused))uint32_t v2)
5199 {
5200     if (((fw->buf[k] & 0xFF1FF000) == 0xE51F0000) &&    // LDR R0, =base
5201         (fw->buf[k+1] == 0xE5D01000) &&                 // LDRB R1, [R0]
5202         (fw->buf[k+2] == 0xE3811002) &&                 // ORR R1, R1, #2
5203         (fw->buf[k+3] == 0xE5C01000) &&                 // STRB R1, [R0]
5204         isBX_LR(fw,k+4))                                // BX LR
5205     {
5206         uint32_t base = LDR2val(fw,k);
5207         print_stubs_min(fw,"full_screen_refresh",base,idx2adr(fw,k));
5208     }
5209     return 0;
5210 }
5211 
5212 int match_canon_shoot_menu_active(firmware *fw, int k, __attribute__ ((unused))uint32_t v1, __attribute__ ((unused))uint32_t v2)
5213 {
5214     if (((fw->buf[k]   & 0xFF1FF000) == 0xE51F1000) &&  // LDR R1, =base
5215         ((fw->buf[k+1] & 0xFFFFF000) == 0xE5D10000) &&  // LDRB R0, [R1, #n]
5216         (fw->buf[k+2] == 0xE2800001) &&                 // ADD R0, R0, #1
5217         ((fw->buf[k+3] & 0xFFFFF000) == 0xE5C10000) &&  // STRB R0, [R1, #n]
5218         (isB(fw,k+4)))                                  // B
5219     {
5220         uint32_t base = LDR2val(fw,k);
5221         uint32_t ofst = fw->buf[k+1] & 0x00000FFF;
5222         print_stubs_min(fw,"canon_shoot_menu_active",base+ofst,idx2adr(fw,k));
5223     }
5224     else
5225     if (((fw->buf[k]   & 0xFF1FF000) == 0xE51F0000) &&  // LDR R0, =base
5226         ((fw->buf[k+1] & 0xFFFFF000) == 0xE5D01000) &&  // LDRB R1, [R0, #n]
5227         (fw->buf[k+2] == 0xE2811001) &&                 // ADD R1, R1, #1
5228         ((fw->buf[k+3] & 0xFFFFF000) == 0xE5C01000) &&  // STRB R1, [R0, #n]
5229         (isB(fw,k+4)))                                  // B
5230     {
5231         uint32_t base = LDR2val(fw,k);
5232         uint32_t ofst = fw->buf[k+1] & 0x00000FFF;
5233         print_stubs_min(fw,"canon_shoot_menu_active",base+ofst,idx2adr(fw,k));
5234     }
5235     return 0;
5236 }
5237 
5238 int match_playrec_mode(firmware *fw, int k, __attribute__ ((unused))uint32_t v1, __attribute__ ((unused))uint32_t v2)
5239 {
5240     if (((fw->buf[k]    & 0xFF1FF000) == 0xE51F1000) && // LDR R1, =base
5241         ((fw->buf[k+1]  & 0xFFFFF000) == 0xE5810000) && // STR R0, [R1, #n]
5242         ((fw->buf[k+3]  & 0xFF1FF000) == 0xE51F0000) && // LDR R0, =base
5243         ((fw->buf[k+4]  & 0xFFFFF000) == 0xE5900000) && // LDR R0, [R0, #n]
5244         ((fw->buf[k+6]  & 0xFF1FF000) == 0xE51F1000) && // LDR R1, =base
5245         ((fw->buf[k+9]  & 0xFF1FF000) == 0xE51F0000) && // LDR R0, =base
5246         ((fw->buf[k+12] & 0xFF1FF000) == 0xE51F1000) && // LDR R1, =base
5247         ((fw->buf[k+15] & 0xFF1FF000) == 0xE51F0000) && // LDR R0, =base
5248         ((fw->buf[k+18] & 0xFF1FF000) == 0xE51F1000) && // LDR R1, =base
5249         (LDR2val(fw,k) == LDR2val(fw,k+3)) &&
5250         (LDR2val(fw,k) == LDR2val(fw,k+6)) &&
5251         (LDR2val(fw,k) == LDR2val(fw,k+9)) &&
5252         (LDR2val(fw,k) == LDR2val(fw,k+12)) &&
5253         (LDR2val(fw,k) == LDR2val(fw,k+15)) &&
5254         (LDR2val(fw,k) == LDR2val(fw,k+18)))
5255     {
5256         uint32_t base = LDR2val(fw,k);
5257         uint32_t ofst = fw->buf[k+1] & 0x00000FFF;
5258         print_stubs_min(fw,"playrec_mode",base+ofst,idx2adr(fw,k));
5259     }
5260     return 0;
5261 }
5262 
5263 int match_some_flag_for_af_scan(firmware *fw, int k, __attribute__ ((unused))uint32_t v1, __attribute__ ((unused))uint32_t v2)
5264 {
5265     if (isB(fw,k)   &&  // B loc
5266         isB(fw,k+1) &&  // B loc
5267         isB(fw,k+2) &&  // B loc
5268         isB(fw,k+3) &&  // B loc
5269         isB(fw,k+4) &&  // B loc
5270         isB(fw,k+5) &&  // B loc
5271         isB(fw,k+6) &&  // B loc
5272         isB(fw,k+7) &&  // B loc
5273         (followBranch(fw,idx2adr(fw,k),1) != followBranch(fw,idx2adr(fw,k+1),1)) &&
5274         (followBranch(fw,idx2adr(fw,k),1) == followBranch(fw,idx2adr(fw,k+2),1)) &&
5275         (followBranch(fw,idx2adr(fw,k),1) == followBranch(fw,idx2adr(fw,k+3),1)) &&
5276         (followBranch(fw,idx2adr(fw,k),1) != followBranch(fw,idx2adr(fw,k+4),1)) &&
5277         (followBranch(fw,idx2adr(fw,k),1) != followBranch(fw,idx2adr(fw,k+5),1)) &&
5278         (followBranch(fw,idx2adr(fw,k),1) == followBranch(fw,idx2adr(fw,k+6),1)) &&
5279         (followBranch(fw,idx2adr(fw,k),1) == followBranch(fw,idx2adr(fw,k+7),1)) &&
5280         (isLDR_PC(fw,adr2idx(fw,followBranch(fw,idx2adr(fw,k),1)))))    // LDR R0, =base
5281     {
5282         uint32_t base = LDR2val(fw,adr2idx(fw,followBranch(fw,idx2adr(fw,k),1)));
5283         if (base < fw->base)
5284             print_stubs_min(fw,"some_flag_for_af_scan",base,followBranch(fw,idx2adr(fw,k),1));
5285     }
5286     return 0;
5287 }
5288 
5289 int match_palette_data(firmware *fw, int k, __attribute__ ((unused))uint32_t v1, __attribute__ ((unused))uint32_t v2)
5290 {
5291     if ((fw->buf[k] == 0) && (fw->buf[k+1] == 0x00FF0000) &&
5292         (fw->buf[k+577] == 1) && (fw->buf[k+578] == 0x00FF0000) &&
5293         (fw->buf[k+1154] == 2) && (fw->buf[k+1155] == 0x00FF0000))
5294     {
5295         return idx2adr(fw,k);
5296     }
5297     else if ((fw->buf[k] == 0) && (fw->buf[k+1] == 0x00FF0000) &&
5298              (fw->buf[k+513] == 1) && (fw->buf[k+514] == 0x00FF0000) &&
5299              (fw->buf[k+1026] == 2) && (fw->buf[k+1027] == 0x00FF0000))
5300     {
5301         return idx2adr(fw,k);
5302     }
5303     return 0;
5304 }
5305 
5306 int match_palette_buffer_offset(firmware *fw, int k)
5307 {
5308     int idx2 = idxFollowBranch(fw, k, 0x01000001);
5309     if (isLDR(fw, idx2+2) && isBL(fw, idx2+3))
5310     {
5311         uint32_t palette_size = LDR2val(fw,idx2+2);
5312         if (palette_size >= 0x400)
5313         {
5314             bprintf("// Offset from start of palette_buffer to color data = %d (Found @0x%08x)\n",palette_size-0x400,idx2adr(fw,idx2+2));
5315             return 1;
5316         }
5317     }
5318     else if (isADR(fw, idx2+2) && isBL(fw, idx2+3))
5319     {
5320         uint32_t palette_size = ALUop2(fw,idx2+2);
5321         if (palette_size >= 0x400)
5322         {
5323             bprintf("// Offset from start of palette_buffer to color data = %d (Found @0x%08x)\n",palette_size-0x400,idx2adr(fw,idx2+2));
5324             return 1;
5325         }
5326     }
5327     return 0;
5328 }
5329 
5330 int match_palette_data3(firmware *fw, int k, uint32_t palette_data, __attribute__ ((unused))uint32_t v2)
5331 {
5332     if (isLDR_PC(fw, k) && (LDR2val(fw,k) == palette_data) && isLDR_PC(fw,k-1) && isLDR_PC(fw,k-6) && isLDR(fw,k-5))
5333     {
5334         uint32_t palette_control = LDR2val(fw,k-6);
5335         int ptr_offset = fwOp2(fw,k-5);
5336         uint32_t fadr = find_inst_rev(fw, isSTMFD_LR, k-7, 30);
5337         if (fadr > 0)
5338         {
5339             int k1 = search_fw(fw, find_B, fadr, 0, 1);
5340             if ((k1 > 0) && isLDR_PC(fw,k1-2) && isLDR(fw,k1-1) && (LDR2val(fw,k1-2) == palette_control))
5341             {
5342                 int active_offset = fwOp2(fw,k1-1);
5343                 print_stubs_min(fw,"active_palette_buffer",palette_control+active_offset,idx2adr(fw,k1-1));
5344                 print_stubs_min(fw,"palette_buffer_ptr",palette_control+ptr_offset,idx2adr(fw,k-5));
5345                 if (isBL(fw,k+8))
5346                 {
5347                     fadr = followBranch(fw, idx2adr(fw,k+8), 0x01000001);
5348                     int idx = adr2idx(fw, fadr);
5349                     if (isLDR(fw, idx+2) && isBL(fw, idx+3))
5350                     {
5351                         uint32_t palette_size = LDR2val(fw,idx+2);
5352                         if (palette_size >= 0x400)
5353                         {
5354                             bprintf("// Offset from start of palette_buffer to color data = %d (Found @0x%08x)\n",palette_size-0x400,idx2adr(fw,idx+2));
5355                         }
5356                     }
5357                 }
5358                 return 1;
5359             }
5360         }
5361     }
5362     return 0;
5363 }
5364 
5365 int match_palette_data2(firmware *fw, int k, uint32_t v1, uint32_t v2)
5366 {
5367     if (isLDR(fw,k) && (LDR2val(fw,k) == v1))
5368     {
5369         int k1;
5370         for (k1=k+1; k1<k+20; k1++)
5371         {
5372             if (isBL(fw,k1) && isLDMFD(fw,k1+2))
5373             {
5374                 uint32_t fadr = followBranch(fw, idx2adr(fw,k1), 0x01000001);
5375                 int idx = adr2idx(fw, fadr);
5376                 int k2;
5377                 for (k2=idx; k2<idx+40; k2++)
5378                 {
5379                     if (isSTR(fw,k2) && isLDMFD(fw,k2+1))
5380                     {
5381                         int ptr_offset = fwval(fw,k2) & 0xFFF;
5382                         print_stubs_min(fw,"palette_buffer_ptr",v2+ptr_offset,idx2adr(fw,k2));
5383                         int found = 0;
5384                         for (k=idx; (k<idx+16) && !found; k++)
5385                         {
5386                             if (isBL(fw,k) && isCMP(fw,k+1) && isADR_PC(fw,k+2))
5387                             {
5388                                 fadr = ADR2adr(fw,k+2);
5389                                 idx = adr2idx(fw, fadr);
5390                                 int k3;
5391                                 for (k3=idx; (k3<idx+16) && !found; k3++)
5392                                 {
5393                                     if (isBL(fw,k3))
5394                                     {
5395                                         if (match_palette_buffer_offset(fw,k3))
5396                                             return 1;
5397                                     }
5398                                 }
5399                             }
5400                         }
5401                         return 1;
5402                     }
5403                 }
5404             }
5405             else if (isLDR_cond(fw,k1) && isLDMFD(fw,k1+2) && isBL(fw,k1-2))
5406             {
5407                 int ptr_offset = fwval(fw,k1) & 0xFFF;
5408                 print_stubs_min(fw,"palette_buffer_ptr",v2+ptr_offset,idx2adr(fw,k1));
5409                 match_palette_buffer_offset(fw, k1-2);
5410                 return 1;
5411             }
5412         }
5413     }
5414     return 0;
5415 }
5416 
5417 int match_SavePaletteData(firmware *fw, int idx, int palette_data)
5418 {
5419     if (isBL(fw,idx+13))
5420     {
5421         uint32_t fadr = followBranch(fw, idx2adr(fw,idx+13), 0x01000001);
5422         idx = adr2idx(fw, fadr);
5423         if (isLDR(fw,idx) && isLDR(fw,idx+1) && isB(fw,idx+2))
5424         {
5425             uint32_t palette_control = LDR2val(fw,idx);
5426             print_stubs_min(fw,"palette_control",palette_control,idx2adr(fw,idx));
5427             int active_offset = fwval(fw,idx+1) & 0xFFF;
5428             print_stubs_min(fw,"active_palette_buffer",palette_control+active_offset,idx2adr(fw,idx+1));
5429             fadr = followBranch(fw,idx2adr(fw,idx+2),1);
5430             idx = adr2idx(fw, fadr);
5431             if (isLDR(fw,idx+17) && isLDR(fw,idx+18) && isLDR(fw,idx+12) && (LDR2val(fw,idx+12) == palette_control))
5432             {
5433                 if (isLDR(fw,idx+13))
5434                 {
5435                     int ptr_offset = fwval(fw,idx+13) & 0xFFF;
5436                     print_stubs_min(fw,"palette_buffer_ptr",palette_control+ptr_offset,idx2adr(fw,idx+13));
5437                 }
5438                 int palette_buffer;
5439                 if ((fwval(fw,idx+18) & 0x0000F000) == 0)
5440                 {
5441                     palette_buffer = LDR2val(fw,idx+17);
5442                     print_stubs_min(fw,"palette_buffer",palette_buffer,idx2adr(fw,idx+17));
5443                 }
5444                 else
5445                 {
5446                     palette_buffer = LDR2val(fw,idx+18);
5447                     print_stubs_min(fw,"palette_buffer",palette_buffer,idx2adr(fw,idx+18));
5448                 }
5449                 if (isBL(fw,idx+26))
5450                 {
5451                     fadr = followBranch(fw, idx2adr(fw,idx+26), 0x01000001);
5452                     idx = adr2idx(fw, fadr);
5453                     if (isLDR(fw, idx+2) && isBL(fw, idx+3))
5454                     {
5455                         uint32_t palette_size = LDR2val(fw,idx+2);
5456                         if (palette_size >= 0x400)
5457                         {
5458                             bprintf("// Offset from start of palette_buffer to color data = %d (Found @0x%08x)\n",palette_size-0x400,idx2adr(fw,idx+2));
5459                         }
5460                     }
5461                 }
5462             }
5463         }
5464         else if (isLDR(fw,idx) && isLDR(fw,idx+6) && isLDR(fw,idx+7) && isBX(fw,idx+8))
5465         {
5466             int active_offset = -1;
5467             if ((fwval(fw,idx+6) & 0x0000F000) == 0)
5468                 active_offset = fwval(fw,idx+6) & 0xFFF;
5469             else if ((fwval(fw,idx+7) & 0x0000F000) == 0)
5470                 active_offset = fwval(fw,idx+7) & 0xFFF;
5471             if (active_offset >= 0)
5472             {
5473                 uint32_t palette_control = LDR2val(fw,idx);
5474                 //print_stubs_min(fw,"palette_control",palette_control,idx2adr(fw,idx));
5475                 print_stubs_min(fw,"active_palette_buffer",palette_control+active_offset,idx2adr(fw,idx+1));
5476                 search_fw(fw, match_palette_data2, palette_data, palette_control, 1);
5477             }
5478         }
5479         return 1;
5480     }
5481 
5482     return 0;
5483 }
5484 
5485 int match_viewport_address3(firmware *fw, int k, uint32_t v1, __attribute__ ((unused))uint32_t v2)
5486 {
5487     if (isLDR_PC(fw,k) && (LDR2val(fw,k) == v1))
5488     {
5489         // Scan back to start of function
5490         int k1 = find_inst_rev(fw, isSTMFD_LR, k-1, 1000);
5491         if (k1 > 0)
5492         {
5493             // Check if function sig matches what we want
5494             if (isLDR_PC(fw,k1+1) && isLDR_PC(fw,k1+2) && isLDR(fw,k1+3) &&
5495                 (fwRd(fw,k1+1) == fwRn(fw,k1+3)))
5496             {
5497                 uint32_t a = LDR2val(fw,k1+1);
5498                 print_stubs_min(fw,"viewport_buffers",v1,idx2adr(fw,k));
5499                 print_stubs_min(fw,"active_viewport_buffer",a,idx2adr(fw,k1+1));
5500                 return 1;
5501             }
5502             else
5503             if (isLDR_PC(fw,k1+1) && isLDR_PC(fw,k1+3) && isLDR(fw,k1+4) &&
5504                 (fwRd(fw,k1+1) == fwRn(fw,k1+4)))
5505             {
5506                 uint32_t a = LDR2val(fw,k1+1);
5507                 print_stubs_min(fw,"viewport_buffers",v1,idx2adr(fw,k));
5508                 print_stubs_min(fw,"active_viewport_buffer",a,idx2adr(fw,k1+1));
5509                 return 1;
5510             }
5511             else
5512             if (isLDR_PC(fw,k1+1) && isLDR_PC(fw,k1+4) && isLDR(fw,k1+5) &&
5513                 (fwRd(fw,k1+1) == fwRn(fw,k1+5)))
5514             {
5515                 uint32_t a = LDR2val(fw,k1+1);
5516                 print_stubs_min(fw,"viewport_buffers",v1,idx2adr(fw,k));
5517                 print_stubs_min(fw,"active_viewport_buffer",a,idx2adr(fw,k1+1));
5518                 return 1;
5519             }
5520         }
5521     }
5522     return 0;
5523 }
5524 
5525 int match_viewport_address2(firmware *fw, int k, uint32_t v1, __attribute__ ((unused))uint32_t v2)
5526 {
5527     if (fw->buf[k] == v1)
5528     {
5529         if (search_fw(fw, match_viewport_address3, v1, 0, 1))
5530             return 1;
5531     }
5532     return 0;
5533 }
5534 
5535 int match_viewport_address(firmware *fw, int k, uint32_t v1, __attribute__ ((unused))uint32_t v2)
5536 {
5537     if (fw->buf[k] == v1)
5538     {
5539         // Find location in firmware that points to viewport address
5540         if (search_fw(fw, match_viewport_address2, idx2adr(fw,k), 0, 1))
5541             return 1;
5542     }
5543     return 0;
5544 }
5545 
5546 int match_physw_status(firmware *fw, int k, __attribute__ ((unused))int v)
5547 {
5548     if (isLDR_PC(fw,k))
5549     {
5550         print_stubs_min(fw,"physw_status",LDR2val(fw,k),idx2adr(fw,k));
5551     }
5552 
5553     return 0;
5554 }
5555 
5556 int match_physw_run(firmware *fw, int k, __attribute__ ((unused))int v)
5557 {
5558     if (isLDR_PC(fw,k))
5559     {
5560         uint32_t base = LDR2val(fw,k);
5561         uint32_t fadr = followBranch(fw, idx2adr(fw,k+1), 1);
5562         uint32_t ofst = fw->buf[adr2idx(fw,fadr)] & 0x00000FFF;
5563         print_stubs_min(fw,"physw_run",base+ofst,idx2adr(fw,k));
5564 
5565         ofst = fw->buf[k+2] & 0x00000FFF;
5566         print_stubs_min(fw,"physw_sleep_delay",base+ofst,idx2adr(fw,k));
5567     }
5568 
5569     return 0;
5570 }
5571 
5572 int match_canon_menu_active(firmware *fw, int k, __attribute__ ((unused))int v)
5573 {
5574     if (isLDR_PC(fw,k))
5575     {
5576         uint32_t base = LDR2val(fw,k);
5577         int k1;
5578         for (k1=k+1; k1<k+5; k1++)
5579         {
5580             if (isLDR(fw,k1))
5581             {
5582                 uint32_t ofst = fw->buf[k1] & 0x00000FFF;
5583                 print_stubs_min(fw,"canon_menu_active",base+ofst,idx2adr(fw,k));
5584             }
5585         }
5586     }
5587 
5588     return 0;
5589 }
5590 
5591 int match_zoom_busy(firmware *fw, int k, __attribute__ ((unused))int v)
5592 {
5593     if (isBL(fw,k))
5594     {
5595         int idx1 = idxFollowBranch(fw,k,0x01000001);
5596         int k1;
5597         for (k1=idx1; k1<idx1+50; k1++)
5598         {
5599             if ((fw->buf[k1] & 0xFFFF0000) == 0xE8BD0000)   // LDMFD
5600             {
5601                 uint32_t fadr = 0;
5602                 if (isADR_PC(fw,k1+1))
5603                 {
5604                     fadr = ADR2adr(fw,k1+1);
5605                 }
5606                 else if (isADR_PC(fw,k1+2))
5607                 {
5608                     fadr = ADR2adr(fw,k1+2);
5609                 }
5610                 else if (isADR_PC(fw,k1-3))
5611                 {
5612                     fadr = ADR2adr(fw,k1-3);
5613                 }
5614                 else if (isLDR_PC(fw,k1+1))
5615                 {
5616                     fadr = LDR2val(fw,k1+1);
5617                 }
5618                 else if (isLDR_PC(fw,k1+2))
5619                 {
5620                     fadr = LDR2val(fw,k1+2);
5621                 }
5622                 if (fadr != 0)
5623                 {
5624                     int idx2 = adr2idx(fw,fadr);
5625                     if (isLDR_PC(fw,idx2+1) && isLDR(fw,idx2+2))
5626                     {
5627                         int base = LDR2val(fw,idx2+1);
5628                         int ofst = fw->buf[idx2+2] & 0xFFF;
5629                            print_stubs_min(fw,"zoom_busy",base+ofst-4,fadr);
5630                         break;
5631                     }
5632                 }
5633             }
5634         }
5635     }
5636 
5637     return 0;
5638 }
5639 
5640 int match_focus_busy(firmware *fw, int k, __attribute__ ((unused))int v)
5641 {
5642     if ((fw->buf[k] & 0xFFFF0000) == 0xE8BD0000)   // LDMFD
5643     {
5644         int k1 = 0;
5645         if (isBL(fw,k-2))
5646         {
5647             k1 = idxFollowBranch(fw,k-2,0x01000001);
5648         }
5649         if (isBL(fw,k-1))
5650         {
5651             k1 = idxFollowBranch(fw,k-1,0x01000001);
5652         }
5653         if (k1 != 0)
5654         {
5655             if (isLDR_PC(fw,k1+1) && isLDR(fw,k1+3))
5656             {
5657                 int base = LDR2val(fw,k1+1);
5658                 int ofst = fw->buf[k1+3] & 0xFFF;
5659                    print_stubs_min(fw,"focus_busy",base+ofst-4,idx2adr(fw,k1));
5660                 return 1;
5661             }
5662         }
5663     }
5664 
5665     return 0;
5666 }
5667 
5668 int match_bitmap_buffer2(firmware *fw, int k, int v)
5669 {
5670     uint32_t screen_lock = idx2adr(fw,k);
5671     if (isBL(fw,v) && (followBranch(fw,idx2adr(fw,v),0x01000001) == screen_lock) && isBL(fw,v+2) && isBL(fw,v+3))
5672     {
5673         uint32_t fadr = followBranch2(fw,idx2adr(fw,v+3),0x01000001);
5674         int k1 = adr2idx(fw,fadr);
5675         if (isLDR_PC(fw,k1+1))
5676         {
5677             uint32_t reg = (fwval(fw,k1+1) & 0x0000F000) >> 12;
5678             uint32_t adr = LDR2val(fw,k1+1);
5679             int k2;
5680             for (k2=k1; k2<k1+32; k2++)
5681             {
5682                 if (isLDR_PC(fw,k2) && isLDR(fw,k2+1) && (((fwval(fw,k2+1) & 0x000F0000) >> 16) == reg))
5683                 {
5684                     uint32_t bitmap_buffer = LDR2val(fw,k2);
5685                     if (bitmap_buffer == (adr + 0x1C))
5686                     {
5687                         uint32_t active_bitmap_buffer = adr + (fwval(fw,k2+1) & 0xFFF);
5688                         print_stubs_min(fw,"bitmap_buffer",bitmap_buffer,idx2adr(fw,k2));
5689                         print_stubs_min(fw,"active_bitmap_buffer",active_bitmap_buffer,idx2adr(fw,k2+1));
5690                     }
5691                 }
5692             }
5693         }
5694     }
5695 
5696     return 0;
5697 }
5698 
5699 int match_bitmap_buffer(firmware *fw, int k, __attribute__ ((unused))int v)
5700 {
5701     search_saved_sig(fw, "ScreenLock", match_bitmap_buffer2, k, 0, 1);
5702     return 0;
5703 }
5704 
5705 int match_raw_buffer(firmware *fw, int k, uint32_t rb1, __attribute__ ((unused))uint32_t v2)
5706 {
5707     if (((fwval(fw,k) == rb1) && (fwval(fw,k+4) == rb1) && (fwval(fw,k-2) != 1) && (fwval(fw,k+2) >= fw->uncached_adr)) ||
5708         ((fwval(fw,k) == rb1) && (fwval(fw,k+4) == rb1) && (fwval(fw,k+20) == rb1)))
5709     {
5710         uint32_t rb2 = fwval(fw,k+1);
5711         if ((rb1 != rb2) && (rb2 > 0))
5712         {
5713             bprintf("// Camera has 2 RAW buffers @ 0x%08x & 0x%08x\n", rb1, rb2, idx2adr(fw,k));
5714             bprintf("//  Note: active buffer --> raw_buffers[active_raw_buffer]\n");
5715             bprintf("//        other buffer  --> raw_buffers[active_raw_buffer^1]\n");
5716             print_stubs_min(fw,"raw_buffers",idx2adr(fw,k),idx2adr(fw,k));
5717         }
5718         return rb2;
5719     }
5720     else if ((fwval(fw,k) == rb1) && (fwval(fw,k-2) == 2) && (fwval(fw,k-7) == rb1))
5721     {
5722         uint32_t rb2 = fwval(fw,k+3);
5723         if ((rb1 != rb2) && (rb2 > 0))
5724         {
5725             bprintf("// Camera has 2 RAW buffers @ 0x%08x & 0x%08x\n", rb1, rb2, idx2adr(fw,k));
5726             bprintf("//  Note: active buffer --> raw_buffers[ active_raw_buffer   *3]\n");
5727             bprintf("//        other buffer  --> raw_buffers[(active_raw_buffer^1)*3]\n");
5728             print_stubs_min(fw,"raw_buffers",idx2adr(fw,k),idx2adr(fw,k));
5729         }
5730         return rb2;
5731     }
5732     return 0;
5733 }
5734 
5735 int match_fileiosem(firmware *fw, int k, uint32_t fadr, uint32_t nadr)
5736 {
5737     if ((k > 5) && isADR_PC(fw, k) && isBL(fw,k+1) && (ADR2adr(fw,k) == nadr) && (followBranch2(fw, idx2adr(fw,k+1), 0x01000001) == fadr))
5738     {
5739         int j, rn = -1;
5740         for (j = k-1; j > k-5; j++)
5741         {
5742             if (isLDR(fw,j))
5743             {
5744                 if (fwRd(fw,j) == 0)
5745                     rn = fwRn(fw, j);
5746                 else if (fwRd(fw,j) == rn)
5747                 {
5748                     int v = LDR2val(fw,j);
5749                     print_stubs_min(fw,"fileio_semaphore",v,idx2adr(fw,j));
5750                     return 1;
5751                 }
5752             }
5753         }
5754     }
5755     return 0;
5756 }
5757 
5758 int match_cameracon_state(firmware *fw, int k, __attribute__ ((unused))int v)
5759 {
5760     /*
5761      * expect
5762      * LDR  Rn, =const
5763      * MOV  Rm, 0
5764      * STR  Rm, [Rn + 0x10] (or 0x1c, on ixus1000)
5765      */
5766     if (isLDR_PC(fw,k))
5767     {
5768         uint32_t base = LDR2val(fw,k);
5769         int k1;
5770         for (k1=k+1; k1<k+4; k1++)
5771         {
5772             if (isSTR(fw,k1))
5773             {
5774                 uint32_t ofst = fw->buf[k1] & 0x00000FFF;
5775                 if(ofst == 0x10 || (fw->dryos_ver == 45 && ofst == 0x1c)) {
5776                     print_stubs_min(fw,"cameracon_state",base+ofst,idx2adr(fw,k));
5777                 }
5778             }
5779         }
5780     }
5781 
5782     return 0;
5783 }
5784 
5785 
5786 // Search for things that go in 'stubs_min.S'
5787 void find_stubs_min(firmware *fw)
5788 {
5789     int k,k1;
5790 
5791     out_hdr = 1;
5792     add_blankline();
5793 
5794     bprintf("// Values below can be overridden in 'stubs_min.S':\n");
5795 
5796     // Find 'physw_status'
5797     search_saved_sig(fw, "kbd_read_keys", match_physw_status, 0, 0, 5);
5798 
5799     // Find 'physw_run' & 'physw_sleep_delay'
5800     search_saved_sig(fw, "task_PhySw", match_physw_run, 0, 0, 5);
5801 
5802     // Find 'levent_table'
5803     search_fw(fw, match_levent_table, 0, 0, 1);
5804 
5805     // Find 'FlashParamsTable'
5806     if (FlashParamsTable_address != 0)
5807         print_stubs_min(fw,"FlashParamsTable",FlashParamsTable_address,FlashParamsTable_address);
5808 
5809     // Find 'movie_status'
5810     search_fw(fw, match_movie_status, 0, 0, 1);
5811 
5812     // Find 'video_compression_rate'
5813     uint32_t sadr = find_str(fw, "CompressionRateAdjuster.c");
5814     k = find_nxt_str_ref(fw, sadr, -1);
5815     int found = 0;
5816     while ((k >= 0) && !found)
5817     {
5818         int f = find_inst_rev(fw, isSTMFD_LR, k-1, 100);
5819         if (f != -1)
5820         {
5821             f = search_fw(fw, find_BL, f, 0, 1);
5822             if (f > 0)
5823             {
5824                 f--;
5825                 if ((fwval(fw,f) & 0xFFF00000) == 0xE2400000)     // SUB
5826                 {
5827                     int src = fwRn(fw,f);
5828                     for (k1 = f-1; (k1 > f-10) && !found; k1--)
5829                     {
5830                         if (isLDR_PC(fw,k1) && (fwRd(fw,k1) == src))
5831                         {
5832                             uint32_t v = LDR2val(fw,k1) - ALUop2(fw,f);
5833                             print_stubs_min(fw,"video_compression_rate",v,idx2adr(fw,k1));
5834                             found = 1;
5835                         }
5836                     }
5837                 }
5838             }
5839         }
5840         k = find_nxt_str_ref(fw, sadr, k);
5841     }
5842 
5843     // Find 'full_screen_refresh'
5844     search_fw(fw, match_full_screen_refresh, 0, 0, 1);
5845 
5846     // Find 'canon_menu_active'
5847     search_saved_sig(fw, "StartRecModeMenu", match_canon_menu_active, 0, 0, 5);
5848 
5849     // Find 'canon_shoot_menu_active'
5850     search_fw(fw, match_canon_shoot_menu_active, 0, 0, 1);
5851 
5852     // Find 'playrec_mode'
5853     int found_playrec_mode = 0;
5854     k = find_str_ref(fw, "AFFChg");
5855     if ((k >= 0) && isBL(fw,k+6))
5856     {
5857         k = idxFollowBranch(fw, k+6, 0x01000001);
5858         if (isLDR_PC(fw,k) && isLDR(fw,k+1))
5859         {
5860             uint32_t base = LDR2val(fw,k);
5861             uint32_t ofst = fw->buf[k+1] & 0x00000FFF;
5862             print_stubs_min(fw,"playrec_mode",base+ofst,idx2adr(fw,k));
5863             found_playrec_mode = 1;
5864         }
5865     }
5866     if (!found_playrec_mode)
5867     {
5868         search_fw(fw, match_playrec_mode, 0, 0, 1);
5869     }
5870 
5871     // Find 'zoom_status'
5872     int found_zoom_status = 0;
5873 
5874     k = find_str_ref(fw, "m_ZoomState            :%d\n");
5875     if (k >= 0)
5876     {
5877         if (isLDR(fw,k-1))
5878         {
5879             uint32_t ofst = fw->buf[k-1] & 0x00000FFF;
5880             uint32_t reg = (fw->buf[k-1] & 0x000F0000) >> 16;
5881             uint32_t ldr_inst = 0xE51F0000 | (reg << 12);
5882             for (k1=k-2; k1>k-20; k1--)
5883             {
5884                 if ((fw->buf[k1] & 0xFF1FF000) == ldr_inst)
5885                 {
5886                     uint32_t base = LDR2val(fw,k1);
5887                     print_stubs_min(fw,"zoom_status",base+ofst,idx2adr(fw,k));
5888                     found_zoom_status = 1;
5889                     break;
5890                 }
5891             }
5892         }
5893     }
5894 
5895     if (!found_zoom_status)
5896     {
5897         for (k=0; k<fw->size; k++)
5898         {
5899             if (((fw->buf[k] & 0xFF1FF000) == 0xE51F0000) &&    // LDR R0, =base
5900                 (fw->buf[k+1] == 0xE5D00000) &&                 // LDRB R0, [R0]
5901                 (fw->buf[k+2] == 0xE1B00000) &&                 // MOVS R0, R0
5902                 (fw->buf[k+3] == 0x13A00001) &&                 // MOVNE R0, #1
5903                 isBX_LR(fw,k+4))                                // BX LR
5904             {
5905                 uint32_t base = LDR2val(fw,k);
5906                 print_stubs_min(fw,"zoom_status",base,idx2adr(fw,k));
5907                 found_zoom_status = 1;
5908                 //break;
5909             }
5910         }
5911     }
5912 
5913     if (!found_zoom_status)
5914     {
5915         k = find_str_ref(fw, "TerminateDeliverToZoomController");
5916         if (k >= 0)
5917         {
5918             for (k1=0; k1<5; k1++)
5919             {
5920                 if (isLDR_PC(fw,k+k1))
5921                 {
5922                     uint32_t base = LDR2val(fw,k+k1);
5923                     print_stubs_min(fw,"zoom_status",base+0x20,idx2adr(fw,k+k1));
5924                     found_zoom_status = 1;
5925                     break;
5926                 }
5927             }
5928         }
5929     }
5930 
5931     // Find 'some_flag_for_af_scan'
5932     search_fw(fw, match_some_flag_for_af_scan, 0, 0, 1);
5933 
5934     // focus_len_table
5935     if (fw->sv->min_focus_len != 0)
5936     {
5937         int found = 0, pos = 0, len = 0, size = 0;
5938         for (k=0; k<fw->size; k++)
5939         {
5940             if (fw->buf[k] == fw->sv->min_focus_len)
5941             {
5942                 int mul = 1;
5943                 if ((fw->buf[k+1] == 100) && (fw->buf[k+2] == 0)) mul = 3;
5944                 if ((fw->buf[k+1] == 100) && (fw->buf[k+2] != 0)) mul = 2;
5945                 if ((fw->buf[k+1] ==   0) && (fw->buf[k+2] != 0)) mul = 2;
5946                 for (k1 = k + mul; (k1 < fw->size) && (fw->buf[k1] > fw->buf[k1-mul]) && (fw->buf[k1] > fw->sv->min_focus_len) && (fw->buf[k1] < fw->sv->max_focus_len); k1 += mul) ;
5947                 if (fw->buf[k1] == fw->sv->max_focus_len)
5948                 {
5949                     int nlen = ((k1 - k) / mul) + 1;
5950                     // printf("FOCUS_LEN_TABLE: %08x %d %d %d %d %d\n", k+fw->base, found, size, mul, len, nlen);
5951                     // Record first table found, or update if better table found - prefer longer entries or longer table with same size entries
5952                     if ((found == 0) || (size < mul) || ((size == mul) && (len < nlen)))
5953                     {
5954                         found = 1;
5955                         pos = k;
5956                         len = nlen;
5957                         size = mul;
5958                     }
5959                 }
5960             }
5961         }
5962         if (found == 1)
5963         {
5964             bprintf("// focus_len_table contains zoom focus lengths for use in 'get_focal_length' (main.c).\n");
5965             if (size == 1)
5966                 bprintf("// each entry contains 1 int value, which is the the zoom focus length.\n",size);
5967             else
5968                 bprintf("// each entry contains %d int value(s), the first is the zoom focus length.\n",size);
5969             bprintf("// there are %d entries in the table - set NUM_FL to %d\n",len,len);
5970             print_stubs_min(fw,"focus_len_table",idx2adr(fw,pos),idx2adr(fw,pos));
5971         }
5972     }
5973 
5974     // Find 'zoom_busy'
5975     search_saved_sig(fw, "ResetZoomLens", match_zoom_busy, 0, 0, 5);
5976 
5977     // Find 'focus_busy'
5978     search_saved_sig(fw, "ResetFocusLens", match_focus_busy, 0, 0, 25);
5979 
5980     // Find 'recreview_hold'
5981     k = find_str_ref(fw, "ShootCon_NotifyStartReviewHold");
5982     if (k >= 0)
5983     {
5984         for (k1=k; k1<k+20; k1++)
5985         {
5986             if (isLDR_PC(fw,k1) && ((fw->buf[k1+1] & 0xFFFF0FFF) == 0xE3A00001) && isSTR(fw,k1+2) &&
5987                 ((fw->buf[k1+1] & 0x0000F000) == (fw->buf[k1+2] & 0x0000F000)) &&
5988                 ((fw->buf[k1] & 0x0000F000) == ((fw->buf[k1+2] & 0x000F0000) >> 4)))
5989             {
5990                 uint32_t base = LDR2val(fw,k1);
5991                 int ofst = fw->buf[k1+2] & 0x00000FFF;
5992                 print_stubs_min(fw,"recreview_hold",base+ofst,idx2adr(fw,k1));
5993                 break;
5994             }
5995         }
5996     }
5997 
5998     // Find palette colour data
5999     uint32_t palette_data = search_fw(fw, match_palette_data, 0, 0, 1);
6000 
6001     // Find 'palette buffer' info
6002     if (palette_data)
6003     {
6004         bprintf("// Palette colour tables  found @ 0x%08x\n", palette_data);
6005         if (search_saved_sig(fw, "SavePaletteData", match_SavePaletteData, palette_data, 0, 1) == 0)
6006         {
6007             search_fw(fw, match_palette_data3, palette_data, 0, 1);
6008         }
6009     }
6010 
6011     // Find 'bitmap buffer' info
6012     search_saved_sig(fw, "GUISrv_StartGUISystem", match_bitmap_buffer, 0, 0, 50);
6013 
6014     // Get viewport address
6015     uint32_t v = find_viewport_address(fw,&k);
6016     if (k >= 0)
6017     {
6018         search_fw(fw, match_viewport_address, v, 0, 1);
6019     }
6020 
6021     // find 1st RAW buffer address
6022     k = find_str_ref(fw, "CRAW BUFF       %p");
6023     if (k >= 0)
6024     {
6025         int rb1_idx;
6026         uint32_t rb1 =0, rb2 = 0;
6027         if (isLDR(fw,k-1))
6028         {
6029             rb1 = LDR2val(fw,k-1);
6030             rb1_idx = k - 1;
6031         }
6032         else if (isMOV_immed(fw,k-1))
6033         {
6034             rb1 = ALUop2(fw,k-1);
6035             rb1_idx = k - 1;
6036         }
6037         else if (isMOV(fw,k-1) && (fwRd(fw,k-1) == 1))
6038         {
6039             int reg = fwval(fw,k-1) & 0xF;
6040             for (k1=k-2; k1>k-50; k1--)
6041             {
6042                 if (isLDR(fw,k1) && (fwRd(fw,k1) == reg))
6043                 {
6044                     rb1 = LDR2val(fw,k1);
6045                     rb1_idx = k1;
6046                     break;
6047                 }
6048             }
6049         }
6050         if (rb1 > 0)
6051         {
6052             found = 0;
6053             rb2 = search_fw(fw, match_raw_buffer, rb1, 0, 5);
6054             if ((rb2 > 0) && (rb1 != rb2))
6055             {
6056                 // Find 'active_raw_buffer'
6057                 sadr = find_str(fw, "SsImgProcBuf.c");
6058                 k = find_nxt_str_ref(fw, sadr, -1);
6059                 while ((k >= 0) && !found)
6060                 {
6061                     int f = find_inst_rev(fw, isSTMFD_LR, k-1, 100);
6062                     if (f != -1)
6063                     {
6064                         int e = find_inst(fw, isLDMFD_PC, f+1, 200);
6065                         for (k1 = f+1; k1 < e; k1++)
6066                         {
6067                             if (
6068                                 (
6069                                     ((fwval(fw,k1)   & 0xFFF00FFF) == 0xE2400001) &&    // SUB Rx, Rn, #1
6070                                     isLDR(fw,k1+1) &&                                   // LDR Ry, [Rz,
6071                                     ((fwval(fw,k1+2) & 0xFFF00000) == 0xE1500000) &&    // CMP Rx, Ry
6072                                     (((fwRd(fw,k1) == fwRd(fw,k1+2)) && (fwRd(fw,k1+1) == fwRn(fw,k1+2))) ||
6073                                      ((fwRd(fw,k1) == fwRn(fw,k1+2)) && (fwRd(fw,k1+1) == fwRd(fw,k1+2)))) &&
6074                                     ((fwval(fw,k1+3) & 0xFFF00FFF) == 0x12800001) &&    // ADDNE Ry, Ry, #1
6075                                     ((fwRd(fw,k1+3) == fwRn(fw,k1+3)) && (fwRd(fw,k1+3) == fwRd(fw,k1+1))) &&
6076                                     ((fwval(fw,k1+4) & 0xFFF00FFF) == 0x03A00000) &&    // MOVEQ Ry, #0
6077                                     (fwRd(fw,k1+4) == fwRd(fw,k1+1)) &&
6078                                     isSTR(fw,k1+5) &&                                   // STR Ry, [Rz,
6079                                     ((fwRd(fw,k1+5) == fwRd(fw,k1+1)) && (fwRn(fw,k1+5) == fwRn(fw,k1+1)) && (fwOp2(fw,k1+5) == fwOp2(fw,k1+1)))
6080                                 ) ||
6081                                 (
6082                                     ((fwval(fw,k1)   & 0xFFF00FFF) == 0xE2400001) &&    // SUB Rx, Rn, #1
6083                                     isLDR(fw,k1+1) &&                                   // LDR Ry, [Rz,
6084                                     ((fwval(fw,k1+3) & 0xFFF00000) == 0xE1500000) &&    // CMP Rx, Ry
6085                                     (((fwRd(fw,k1) == fwRd(fw,k1+3)) && (fwRd(fw,k1+1) == fwRn(fw,k1+3))) ||
6086                                      ((fwRd(fw,k1) == fwRn(fw,k1+3)) && (fwRd(fw,k1+1) == fwRd(fw,k1+3)))) &&
6087                                     ((fwval(fw,k1+4) & 0xFFF00FFF) == 0x12800001) &&    // ADDNE Ry, Ry, #1
6088                                     ((fwRd(fw,k1+4) == fwRn(fw,k1+4)) && (fwRd(fw,k1+4) == fwRd(fw,k1+1))) &&
6089                                     ((fwval(fw,k1+5) & 0xFFF00FFF) == 0x03A00000) &&    // MOVEQ Ry, #0
6090                                     (fwRd(fw,k1+5) == fwRd(fw,k1+1)) &&
6091                                     isSTR(fw,k1+7) &&                                   // STR Ry, [Rz,
6092                                     ((fwRd(fw,k1+7) == fwRd(fw,k1+1)) && (fwRn(fw,k1+7) == fwRn(fw,k1+1)) && (fwOp2(fw,k1+7) == fwOp2(fw,k1+1)))
6093                                 )
6094                                )
6095                             {
6096                                 int ofst = fwOp2(fw,k1+1);
6097                                 int reg = fwRn(fw,k1+1);
6098                                 int k2;
6099                                 for (k2 = f+1; (k2 < e) && !found; k2++)
6100                                 {
6101                                     if (isLDR_PC(fw,k2) && (fwRd(fw,k2) == reg))
6102                                     {
6103                                         uint32_t base = LDR2val(fw,k2);
6104                                         print_stubs_min(fw,"active_raw_buffer",base+ofst,idx2adr(fw,k1));
6105                                         found = 1;
6106                                         break;
6107                                     }
6108                                 }
6109                             }
6110                         }
6111                     }
6112                     k = find_nxt_str_ref(fw, sadr, k);
6113                 }
6114             }
6115             if (!found)
6116             {
6117                 bprintf("// Camera appears to have only 1 RAW buffer @ 0x%08x (Found @0x%08x)\n", rb1, idx2adr(fw,rb1_idx));
6118             }
6119         }
6120     }
6121 
6122     // Find 'fileio_semaphore'
6123     k = get_saved_sig(fw, "TakeSemaphoreStrictly");
6124     if (k >= 0)
6125     {
6126         uint32_t fadr = func_names[k].val;
6127         k = find_str(fw, "FileSem.c");
6128         if (k >= 0)
6129         {
6130             uint32_t nadr = idx2adr(fw, k);
6131             search_fw(fw, match_fileiosem, fadr, nadr, 3);
6132         }
6133     }
6134 
6135     // Find exmem allocation table
6136     find_exmem_alloc_table(fw);
6137 
6138     // Find imager_active
6139     search_saved_sig(fw, "ImagerActivate", match_imager_active, 0/*v*/, 0, 30);
6140 
6141 //    if (frsp_buf && frsp_param!=-1)
6142 //    {
6143 //        print_stubs_min(fw,"frsp_buf",frsp_buf,frsp_buf_at);
6144 //        bprintf("DEF_CONST(%-34s,0x%08x)\n","frsp_param",frsp_param);
6145 //        bprintf("DEF_CONST(%-34s,0x%08x)\n","frsp_argcnt",frsp_argcnt);
6146 //    }
6147 
6148     // Find UI property count
6149     search_saved_sig(fw, "PTM_SetCurrentItem", match_uiprop_count, 0, 0, 30);
6150 
6151     search_saved_sig(fw, "cameracon_set_state", match_cameracon_state, 0, 1, 1);
6152 }
6153 
6154 //------------------------------------------------------------------------------------------------------------
6155 
6156 int find_ctypes(firmware *fw, int k)
6157 {
6158     static unsigned char ctypes[] =
6159     {
6160         0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x60, 0x60, 0x60, 0x60, 0x60, 0x20, 0x20,
6161         0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
6162         0x48, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
6163         0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
6164         0x10, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 1, 1, 1, 1, 1, 1, 1, 1, 1,
6165         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0x10, 0x10, 0x10, 0x10, 0x10,
6166         0x10, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 2, 2, 2, 2, 2, 2, 2, 2, 2,
6167         2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0x10, 0x10, 0x10, 0x10, 0x20
6168     };
6169 
6170     if ((uint32_t)k < (fw->size*4 - sizeof(ctypes)))
6171     {
6172         if (memcmp(((char*)fw->buf)+k,ctypes,sizeof(ctypes)) == 0)
6173         {
6174             bprintf("DEF(ctypes, 0x%08x)\n", fw->base + k);
6175             return 1;
6176         }
6177     }
6178     return 0;
6179 }
6180 
6181 int match_nrflag3(firmware *fw, int k, uint32_t v1, __attribute__ ((unused))uint32_t v2)
6182 {
6183     if (isBL(fw,k) && (idxFollowBranch(fw,k,0x01000001) == (int)v1))
6184     {
6185         // Found call to function, work out R3 value passed in
6186         int ofst1 = 0;
6187         int k3, k4 = 0;
6188         for (k3=k; k3>k-30; k3--)
6189         {
6190             if ((fwval(fw,k3) & 0x0F0FF000) == 0x020D3000)       // Dest = R3, Src = SP = skip
6191                 break;
6192             if ((fwval(fw,k3) & 0xFF0FF000) == 0xE2033000)       // ADD/SUB R3,R3,x
6193             {
6194                 k4 = k3;
6195                 if ((fwval(fw,k3) & 0x00F00000) == 0x00400000)   // SUB
6196                     ofst1 -= (fwval(fw,k3) & 0x00000FFF);
6197                 else
6198                     ofst1 += (fwval(fw,k3) & 0x00000FFF);
6199             }
6200             if (isLDR_PC(fw,k3) && (fwRd(fw,k3) == 3))
6201             {
6202                 int ofst2 = LDR2val(fw,k3);
6203                 bprintf("\n// For capt_seq.c\n");
6204                 if (ofst1 == 0)
6205                 {
6206                     bprintf("DEF(_nrflag,0x%04x) // Found @ %08x (0x%04x)\n",ofst2,idx2adr(fw,k3),ofst2);
6207                     bprintf("//static long *nrflag = (long*)(0x%04x);       // Found @ %08x\n",ofst2,idx2adr(fw,k3));
6208                 }
6209                 else if (ofst1 < 0)
6210                 {
6211                     bprintf("DEF(_nrflag,0x%04x) // Found @ %08x (0x%04x) & %08x (-0x%02x)\n",ofst2+ofst1,idx2adr(fw,k3),ofst2,idx2adr(fw,k),-ofst1);
6212                     bprintf("//static long *nrflag = (long*)(0x%04x-0x%02x);  // Found @ %08x & %08x\n",ofst2,-ofst1,idx2adr(fw,k3),idx2adr(fw,k4));
6213                 }
6214                 else
6215                 {
6216                     bprintf("DEF(_nrflag,0x%04x) // Found @ %08x (0x%04x) & %08x (+0x%02x)\n",ofst2+ofst1,idx2adr(fw,k3),ofst2,idx2adr(fw,k),ofst1);
6217                     bprintf("//static long *nrflag = (long*)(0x%04x+0x%02x);  // Found @ %08x & %08x\n",ofst2,ofst1,idx2adr(fw,k3),idx2adr(fw,k4));
6218                 }
6219                 return 1;
6220             }
6221         }
6222     }
6223     return 0;
6224 }
6225 
6226 int match_nrflag(firmware *fw, int idx, __attribute__ ((unused))int v)
6227 {
6228     int k1, k2, k3;
6229     int found = 0;
6230 
6231     if (isLDR(fw, idx+1) && isLDR(fw, idx+2))
6232     {
6233         k3 = idx+2;
6234         int ofst2 = LDR2val(fw, k3);
6235 
6236         for (k1=k3+1; k1<k3+8; k1++)
6237         {
6238             if (isB(fw, k1))
6239             {
6240                 k2 = idxFollowBranch(fw,k1,0x01000001);
6241                 if (isSTR(fw, k2))
6242                 {
6243                     found = 1;
6244                     break;
6245                 }
6246                 k2++;
6247                 if (isSTR(fw, k2))
6248                 {
6249                     found = 1;
6250                     break;
6251                 }
6252             }
6253         }
6254 
6255         if (found)
6256         {
6257             int ofst1 = fw->buf[k2] & 0x00000FFF;
6258             bprintf("\n// For capt_seq.c\n");
6259             bprintf("DEF(_nrflag,0x%04x) // Found @ %08x (0x%04x) & %08x (+0x%02x)\n",ofst2+ofst1,idx2adr(fw,k3),ofst2,idx2adr(fw,k2),ofst1);
6260             bprintf("//static long *nrflag = (long*)(0x%04x+0x%02x);  // Found @ %08x & %08x\n",ofst2,ofst1,idx2adr(fw,k3),idx2adr(fw,k2));
6261             bprintf("//#define NR_AUTO (0)                          // have to explictly reset value back to 0 to enable auto\n");
6262         }
6263     }
6264 
6265     return found;
6266 }
6267 
6268 int match_nrflag2(firmware *fw, int k, __attribute__ ((unused))int v)
6269 {
6270     // Found NR_GetDarkSubType function, now follow first BL call.
6271     if (isBL(fw,k))
6272     {
6273         k = idxFollowBranch(fw,k,0x01000001);
6274         return search_fw(fw, match_nrflag3, k, 0, 1);
6275     }
6276 
6277     return 0;
6278 }
6279 
6280 // find LEDs
6281 
6282 // helpers for find_leds()
6283 int isSTRw(firmware *fw, int offset)
6284 {
6285     if ((fwval(fw,offset) & 0xfff00000) == (0xe5800000)) // STR Rx, [Ry, #offs]
6286     {
6287         return 1;
6288     }
6289     return 0;
6290 }
6291 
6292 int isSTRB(firmware *fw, int offset)
6293 {
6294     if ((fwval(fw,offset) & 0xfff00000) == (0xe5c00000)) // STRB Rx, [Ry, #offs]
6295     {
6296         return 1;
6297     }
6298     return 0;
6299 }
6300 
6301 typedef struct {
6302     uint32_t addr;  // LED GPIO address
6303     int reg;        // register used to assemble the address
6304     int offs;       // offset in the LED table
6305     int done;       // already written
6306 } LED_s;
6307 
6308 // an array of 16 LED candidates should be enough
6309 #define LEDMAX 16
6310 
6311 int find_leds(firmware *fw)
6312 {
6313     int j1, j2, j3;
6314     LED_s leds[LEDMAX];
6315     int k0 = find_str_ref(fw,"LEDCon");
6316     if (k0<0)
6317         return 0;
6318     int k1 = find_inst_rev(fw,isSTMFD_LR,k0,110);
6319     if (k1<0)
6320         return 0;
6321     j1 = find_inst(fw,isBL,k1,80);
6322     j2 = find_Nth_inst(fw,isBL,k1,80,3);
6323     if ((j1<0) || (j2<0))
6324         return 0;
6325     j3 = 0; // highest leds[] index
6326     int found;
6327 
6328     memset(leds, 0, sizeof(LED_s)*LEDMAX);
6329 
6330     // in older versions of the routine, 1st and 3rd BL is memory allocation
6331     if (followBranch(fw,idx2adr(fw,j1),0x01000001) == followBranch(fw,idx2adr(fw,j2),0x01000001))
6332     {
6333         k1 = find_Nth_inst(fw,isBL,k1,80,2);
6334         // LED table initializer func
6335         k1 = idxFollowBranch(fw,k1,0x01000001);
6336         if (k1<0)
6337             return 0;
6338         bprintf("\n// LED table init @ 0x%x\n",idx2adr(fw,k1));
6339 
6340         // scan for MMIO addresses loaded via LDR, should work on DIGIC 4 and III cams
6341         // some cameras may have specially handled LEDs, they will not be found
6342         // DIGIC 5 cams will get no hits here
6343         j2 = 0;
6344         j1 = 0;
6345         while (j2 < 32)
6346         {
6347             if (isLDR_PC(fw,k1+j2))
6348             {
6349                 uint32_t l1 = LDR2val(fw,k1+j2);
6350                 if (l1 >= 0xc0220000)
6351                 {
6352                     leds[j3].addr = l1;
6353                     leds[j3].reg = fwRd(fw,k1+j2);
6354                     j3++;
6355                 }
6356             }
6357             else if (isBX_LR(fw,k1+j2) || isB(fw,k1+j2))
6358             {
6359                 break;
6360             }
6361             j2++;
6362             if (j3>=LEDMAX)
6363                 break;
6364         }
6365 
6366         j3--;
6367         j1 = 0;
6368         if (j3 >= 0)
6369         {
6370             int repeatfrom = 0;
6371             int repeatreg = 0;
6372             int repeataddr = 0;
6373             while (j3 >= 0)
6374             {
6375                 // main cycle to parse the LED table init function
6376                 // tries to work out the LED MMIO addresses
6377 
6378                 j2 = 0;
6379                 int gotit = 0;
6380                 if (repeatfrom)
6381                 {
6382                     j2 = repeatfrom;
6383                     leds[j3].reg = repeatreg;
6384                     leds[j3].addr = repeataddr;
6385                     leds[j3].done = 0;
6386                     gotit = 1;
6387                     repeatfrom = 0;
6388                 }
6389                 while (j2 < 32)
6390                 {
6391                     found = 0;
6392                     if (isLDR_PC(fw,k1+j2))
6393                     {
6394                         if (!gotit)
6395                         {
6396                             uint32_t l1 = LDR2val(fw,k1+j2);
6397                             if (l1 >= 0xc0220000)
6398                             {
6399                                 if ((leds[j3].reg == fwRd(fw,k1+j2)) && (leds[j3].addr == LDR2val(fw,k1+j2)))
6400                                 {
6401                                     leds[j3].done = 0;
6402                                     gotit = 1;
6403                                 }
6404                             }
6405                         }
6406                         else
6407                         {
6408                             if (leds[j3].reg == fwRd(fw,k1+j2))
6409                             {
6410                                 break;
6411                             }
6412                         }
6413                     }
6414                     else if (isBX_LR(fw,k1+j2) || isB(fw,k1+j2))
6415                     {
6416                         break;
6417                     }
6418                     if (!gotit)
6419                     {
6420                         // fast forward until the LDR in question is found
6421                         j2++;
6422                         continue;
6423                     }
6424                     if (isADD(fw,k1+j2))
6425                     {
6426                         if (leds[j3].reg == fwRd(fw,k1+j2))
6427                         {
6428                             leds[j3].addr += ALUop2a(fw,k1+j2);
6429                             leds[j3].done = 0;
6430                         }
6431                         else if (leds[j3].reg == fwRn(fw,k1+j2))
6432                         {
6433                             // MMIO address passed to another register, schedule re-entry if possible
6434                             if (!repeatfrom)
6435                             {
6436                                 repeataddr = leds[j3].addr + ALUop2a(fw,k1+j2);
6437                                 repeatreg = fwRd(fw,k1+j2);
6438                                 repeatfrom = j2 + 1;
6439                             }
6440                         }
6441                     }
6442                     else if (isSUB(fw,k1+j2))
6443                     {
6444                         if (leds[j3].reg == fwRd(fw,k1+j2))
6445                         {
6446                             leds[j3].addr -= ALUop2a(fw,k1+j2);
6447                             leds[j3].done = 0;
6448                         }
6449                         else if (leds[j3].reg == fwRn(fw,k1+j2))
6450                         {
6451                             // MMIO address passed to another register, schedule re-entry if possible
6452                             if (!repeatfrom)
6453                             {
6454                                 repeataddr = leds[j3].addr - ALUop2a(fw,k1+j2);
6455                                 repeatreg = fwRd(fw,k1+j2);
6456                                 repeatfrom = j2 + 1;
6457                             }
6458                         }
6459                     }
6460                     else if (isSTR(fw,k1+j2))
6461                     {
6462                         // LED references are always stored with STR, not STRB or STRH
6463                         // check for matching register
6464                         if (leds[j3].reg == fwRd(fw,k1+j2))
6465                         {
6466                             leds[j3].offs = fwval(fw,k1+j2) & 0xfff;
6467                             found = 1;
6468                         }
6469                     }
6470                     else if (isMOV_immed(fw,k1+j2) && (leds[j3].reg == fwRd(fw,k1+j2)))
6471                     {
6472                         // the register holding the MMIO address gets a new value, start again with the next MMIO, if any
6473                         break;
6474                     }
6475                     j2++;
6476                     // output data if valid
6477                     if (found && (!leds[j3].done))
6478                     {
6479                         j1++;
6480                         bprintf("// LED #%i: 0x%08x, offset 0x%x\n",j1, leds[j3].addr, leds[j3].offs);
6481                         leds[j3].done = 1;
6482                     }
6483                 }
6484                 if (!repeatfrom)
6485                 {
6486                     j3--;
6487                 }
6488             }
6489         }
6490         else
6491         {
6492             // DIGIC 5
6493             // LEDs are identified by their location in the GPIO table, not their address
6494             // some LEDs might be "special cased" and not appear in the GPIO table or the LED table init function
6495             // those special cases are not currently handled
6496 
6497             // locate GPIO table first
6498             int gpiotbladdr = 0;
6499             j2 = find_str_ref(fw,"\n\n Set LCD Driver: Address 0x%04x <-- Data 0x%04x\n");
6500             if (j2 > 0)
6501             {
6502                 j2 = find_inst_rev(fw, isBL, j2, 8);
6503                 if (j2 > 0)
6504                 {
6505                     j3 = 2;
6506                     while (j3 > 0)
6507                     {
6508                         if ( !((fwval(fw,j2-1)&0xfffff000)==0xe3a01000) && !((fwval(fw,j2-2)&0xfffff000)==0xe3a01000) ) // MOV R1, #imm
6509                         {
6510                             j2 = find_inst_rev(fw, isBL, j2-1, 6);
6511                         }
6512                         else
6513                         {
6514                             break;
6515                         }
6516                         j3--;
6517                     }
6518                     if (j2 > 0)
6519                     {
6520                         // j2 points to a function that is used to poke GPIOs, based on a GPIO table
6521                         j2 = idxFollowBranch(fw, j2, 0x01000001);
6522                         if (isLDR_PC(fw,j2))
6523                         {
6524                             // 1st instruction references the table's address (could change in the future?)
6525                             gpiotbladdr = adr2idx(fw, LDR2val(fw, j2));
6526                         }
6527                     }
6528                 }
6529             }
6530             // identify the LED(s)
6531             /*
6532              * r0 is a pointer to the LED struct array
6533              * below pattern inits an LED:
6534              * mov rx, #imm
6535              * ...
6536              * strb ry, [r0, #imm2]
6537              * str rx, [r0, #imm2+4]
6538              * the strb pair might be at a different location
6539              */
6540             j2 = 0;
6541             j3 = 0;
6542             while (j2 < 32)
6543             {
6544                 // find str rx, [r0, #imm2+4]
6545                 if (isSTRw(fw,k1+j2))
6546                 {
6547                     uint32_t o1 = fwval(fw,k1+j2)&0xfff; // may not be the correct way of determining the offset
6548                     uint32_t o2 = 0;
6549                     int n = 1;
6550                     int r1 = -1;
6551                     while (n < 32)
6552                     {
6553                         if (isSTRB(fw,k1+n))
6554                         {
6555                             o2 = fwval(fw,k1+n)&0xfff;
6556                             if (o1-4 == o2)
6557                             {
6558                                 r1 = fwRd(fw,k1+j2); // dest. register
6559                             }
6560                         }
6561                         else if (isBX_LR(fw,k1+n) || isB(fw,k1+n))
6562                         {
6563                             break;
6564                         }
6565                         n++;
6566                     }
6567                     if (r1 >= 0)
6568                     {
6569                         // search for that register's content
6570                         n = k1+j2-1;
6571                         while (n >= k1)
6572                         {
6573                             if (isMOV_immed(fw, n) && (fwRd(fw, n) == r1))
6574                             {
6575                                 leds[j3].addr = ALUop2a(fw,n);
6576                                 leds[j3].offs = o1;
6577                                 j3++;
6578                                 break;
6579                             }
6580                             n--;
6581                         }
6582                     }
6583                 }
6584                 else if (isBX_LR(fw,k1+j2) || isB(fw,k1+j2))
6585                 {
6586                     break;
6587                 }
6588                 j2++;
6589                 if (j3 >= LEDMAX)
6590                     break;
6591             }
6592             j3--;
6593             while (j3 >= 0)
6594             {
6595                 j1++;
6596                 if (leds[j3].addr > 0xfff)
6597                 {
6598                     bprintf("// LED #%i: unknown (index: 0x%08x), offset 0x%x\n",j1, leds[j3].addr, leds[j3].offs);
6599                 }
6600                 else if (gpiotbladdr)
6601                 {
6602                     bprintf("// LED #%i: 0x%08x (#%d in GPIO table), offset 0x%x\n",j1, fwval(fw, leds[j3].addr + gpiotbladdr), leds[j3].addr, leds[j3].offs);
6603                 }
6604                 else
6605                 {
6606                     bprintf("// LED #%i:  #%d in GPIO table, offset 0x%x\n",j1, leds[j3].addr, leds[j3].offs);
6607                 }
6608                 j3--;
6609             }
6610             if (gpiotbladdr)
6611             {
6612                 bprintf("// GPIO table @ 0x%x\n",idx2adr(fw, gpiotbladdr));
6613             }
6614         }
6615     }
6616     else
6617     {
6618         // DIGIC 4+
6619         // LEDs are identified by their location in the GPIO table, not their address
6620         // some LEDs might be "special cased" and not appear in the GPIO table or the LED table init function
6621         // those special cases are not currently handled
6622 
6623         int f1 = get_saved_sig(fw,"CreateMessageQueueStrictly");
6624         if (f1 < 0)
6625             return 0;
6626         f1 = adr2idx(fw, func_names[f1].val);
6627 
6628         int n;
6629         k1 = k0; // ref. to "LEDCon"
6630         for (n=0; n<5; n++)
6631         {
6632             k1 = find_inst_rev(fw,isBL,k1-1,80);
6633             if (k1 > 0)
6634             {
6635                 if (idx2adr(fw,idxFollowBranch(fw,k1,0x01000001)) == idx2adr(fw,f1)) // BL CreateMessageQueueStrictly
6636                 {
6637                     n = -1;
6638                     break;
6639                 }
6640             }
6641         }
6642         if (n >= 0)
6643             return 0;
6644         // LED table initializer func, right before CreateMessageQueueStrictly
6645         k1 = find_inst_rev(fw,isBL,k1-1,80);
6646         if (k1<0)
6647             return 0;
6648         k1 = idxFollowBranch(fw,k1,0x01000001);
6649         if (k1<0)
6650             return 0;
6651         bprintf("\n// LED table init @ 0x%x\n",idx2adr(fw,k1));
6652 
6653         // locate GPIO table
6654         j1 = 0;
6655         int gpiotbladdr = 0;
6656         j2 = find_str_ref(fw,"\n\n Set LCD Driver: Address 0x%04x <-- Data 0x%04x\n");
6657         if (j2 > 0)
6658         {
6659             j2 = find_inst_rev(fw, isBL, j2, 8);
6660             if (j2 > 0)
6661             {
6662                 j3 = 2;
6663                 while (j3 > 0)
6664                 {
6665                     if ( !((fwval(fw,j2-1)&0xfffff000)==0xe3a00000) && !((fwval(fw,j2-2)&0xfffff000)==0xe3a00000) ) // MOV R0, #imm
6666                     {
6667                         j2 = find_inst_rev(fw, isBL, j2-1, 6);
6668                     }
6669                     else
6670                     {
6671                         break;
6672                     }
6673                     j3--;
6674                 }
6675                 if (j2 > 0)
6676                 {
6677                     // j2 points to a function that is used to poke GPIOs, based on a GPIO table
6678                     j2 = idxFollowBranch(fw, j2, 0x01000001);
6679                     if (isLDR_PC(fw,j2))
6680                     {
6681                         // 1st instruction references the table's address (could change in the future?)
6682                         gpiotbladdr = adr2idx(fw, LDR2val(fw, j2));
6683                     }
6684                 }
6685             }
6686         }
6687         // identify the LED(s)
6688         /*
6689          * r0 is a pointer to the LED struct array
6690          * below pattern inits an LED:
6691          * mov rx, #imm
6692          * ...
6693          * strb ry, [r0, #imm2]
6694          * str rx, [r0, #imm2+4]
6695          * the strb pair might be at a different location
6696          */
6697         j2 = 0;
6698         j3 = 0;
6699         while (j2 < 32)
6700         {
6701             // find str rx, [r0, #imm2+4]
6702             if (isSTRw(fw,k1+j2))
6703             {
6704                 uint32_t o1 = fwval(fw,k1+j2)&0xfff; // may not be the correct way of determining the offset
6705                 uint32_t o2 = 0;
6706                 int n = 1;
6707                 int r1 = -1;
6708                 while (n < 32)
6709                 {
6710                     if (isSTRB(fw,k1+n))
6711                     {
6712                         o2 = fwval(fw,k1+n)&0xfff;
6713                         if (o1-4 == o2)
6714                         {
6715                             r1 = fwRd(fw,k1+j2); // dest. register
6716                         }
6717                     }
6718                     else if (isBX_LR(fw,k1+n) || isB(fw,k1+n))
6719                     {
6720                         break;
6721                     }
6722                     n++;
6723                 }
6724                 if (r1 >= 0)
6725                 {
6726                     // search for that register's content
6727                     n = k1+j2-1;
6728                     while (n >= k1)
6729                     {
6730                         if (isMOV_immed(fw, n) && (fwRd(fw, n) == r1))
6731                         {
6732                             leds[j3].addr = ALUop2a(fw,n);
6733                             leds[j3].offs = o1;
6734                             j3++;
6735                             break;
6736                         }
6737                         n--;
6738                     }
6739                 }
6740             }
6741             else if (isBX_LR(fw,k1+j2) || isB(fw,k1+j2))
6742             {
6743                 break;
6744             }
6745             j2++;
6746             if (j3 >= LEDMAX)
6747                 break;
6748         }
6749         j3--;
6750         while (j3 >= 0)
6751         {
6752             j1++;
6753             if (leds[j3].addr > 0xfff)
6754             {
6755                 bprintf("// LED #%i: unknown (index: 0x%08x), offset 0x%x\n",j1, leds[j3].addr, leds[j3].offs);
6756             }
6757             else if (gpiotbladdr)
6758             {
6759                 bprintf("// LED #%i: 0x%08x (#%d in GPIO table), offset 0x%x\n",j1, fwval(fw, leds[j3].addr + gpiotbladdr), leds[j3].addr, leds[j3].offs);
6760             }
6761             else
6762             {
6763                 bprintf("// LED #%i:  #%d in GPIO table, offset 0x%x\n",j1, leds[j3].addr, leds[j3].offs);
6764             }
6765             j3--;
6766         }
6767         if (gpiotbladdr)
6768         {
6769             bprintf("// GPIO table @ 0x%x\n",idx2adr(fw, gpiotbladdr));
6770         }
6771     }
6772     return 0;
6773 }
6774 
6775 int find_task_related_info(firmware *fw)
6776 {
6777     int i = get_saved_sig(fw,"get_self_task_id");
6778     uint32_t u, v;
6779     if (i < 0)
6780     {
6781         return 0;
6782     }
6783     i = adr2idx(fw, func_names[i].val);
6784     if ( (fwval(fw,i)&0xffff0000)==0xe59f0000 ) // ldr r0, [pc, #imm]
6785     {
6786         // "interrupt service routine" flag
6787         u = LDR2val(fw, i);
6788         if ( (fwval(fw,i+3)&0xffff0000)==0x059f0000 ) // ldreq r0, [pc, #imm]
6789         {
6790             // pointer to current task's control block
6791             v = LDR2val(fw, i+3);
6792             bprintf("// ISR flag: 0x%x, pointer to current task's control block: 0x%x\n",u, v);
6793         }
6794     }
6795     // part 2, find the TCB area
6796     int j, k, n, fnd;
6797     int m = 0;
6798     i = find_str(fw, "DRYOS version 2.3, release ");
6799     j = find_nxt_str_ref(fw, i, -1);
6800     if (j == -1)
6801     {
6802         // special case: some r50 cams have the string in RAM and all references point there
6803         u = idx2adr(fw,i);
6804         if ( (u > fw->base_copied) && ((u-fw->base_copied)/4 < (uint32_t)fw->size2))
6805         {
6806             i = adr2idx(fw, fw->base2 + (u-fw->base_copied));
6807             j = find_nxt_str_ref(fw, i, -1);
6808         }
6809     }
6810     fnd = 0;
6811     while (!fnd) {
6812         if (j != -1)
6813         {
6814             k = find_nxt_str_ref(fw, i, j+1);
6815             if (k != -1)
6816             {
6817                 if (k-j>5)
6818                 {
6819                     // refs too far, try again
6820                     j = k;
6821                 }
6822                 else
6823                 {
6824                     m = find_inst_rev(fw, isSTMFD_LR, j, 42);
6825                     if (j-m>24)
6826                     {
6827                         fnd = 1;
6828                     }
6829                 }
6830             }
6831         }
6832         else
6833         {
6834             break;
6835         }
6836     }
6837     u = 0;
6838     if (fnd)
6839     {
6840         n = find_Nth_inst(fw, isBL, m, 6, 2);
6841         if (n != -1)
6842         {
6843             n = idxFollowBranch(fw,n,0x01000001);
6844             n = find_inst(fw, isSTR, n, 8);
6845             if (n != -1)
6846             {
6847                 m = fwRn(fw, n);    // this register holds the base address pointer of TCB area
6848                 n = find_inst_rev(fw, isLDR_PC, n-1, 4);
6849                 if (n != -1)
6850                 {
6851                     if (fwRd(fw, n) != m)
6852                     {
6853                         n = find_inst_rev(fw, isLDR_PC, n-1, 3);
6854                         if ((n != -1) && (fwRd(fw, n) == m))
6855                         {
6856                             u = LDR2val(fw, n);
6857                             v = idx2adr(fw, n);
6858                             bprintf("// pointer to TCB area: 0x%x, found @ 0x%x\n",u,v);
6859                         }
6860                     }
6861                 }
6862             }
6863         }
6864     }
6865 
6866 
6867     return 0;
6868 }
6869 
6870 void find_AdditionAgent_RAM(firmware *fw)
6871 {
6872     int i = get_saved_sig(fw,"AdditionAgentRAM_FW");
6873     uint32_t r, sizeloc = 0, startloc = 0;
6874     uint32_t ramsize = 0;
6875     uint32_t ramstart = 0;
6876     if (i >= 0)
6877     {
6878         int j1 = adr2idx(fw, func_names[i].val);
6879         int n;
6880         for (n=1; n<16; n++)
6881         {
6882             if (fwval(fw,j1+n) == 0xe3500a32) // cmp  r0, #0x32000
6883             {
6884                 ramsize = 0x32000;
6885                 sizeloc = idx2adr(fw,j1+n);
6886                 break;
6887             }
6888             else if (fwval(fw,j1+n) == 0xe3500a22) // cmp  r0, #0x22000
6889             {
6890                 ramsize = 0x22000;
6891                 sizeloc = idx2adr(fw,j1+n);
6892                 break;
6893             }
6894         }
6895         if (n >= 15)
6896             n = 0;
6897         j1 += n;
6898         for (n=0; n<=16; n++)
6899         {
6900             r = LDR2val(fw,j1+n);
6901             if ( isLDR_PC(fw,j1+n) && (r>fw->memisostart) && (r<fw->maxram) )
6902             {
6903                 ramstart = r;
6904                 startloc = idx2adr(fw,j1+n);
6905             }
6906         }
6907         if (ramstart>0)
6908         {
6909             bprintf("//   ARAM_HEAP_START = 0x%x# Found @ 0x%08x\n",ramstart,startloc);
6910             bprintf("//   ARAM_HEAP_SIZE  = 0x%x# Found @ 0x%08x\n",ramsize,sizeloc);
6911         }
6912     }
6913 }
6914 
6915 /* propset related stuff */
6916 
6917 // below enum lists propcases that are handled
6918 enum {
6919     PROPCASE_AFSTEP = 0,
6920     PROPCASE_FOCUS_STATE,
6921     PROPCASE_AV,
6922     PROPCASE_BV,
6923     PROPCASE_DELTA_DIGITALGAIN,
6924     PROPCASE_DELTA_SV,
6925     PROPCASE_DELTA_ND,
6926     PROPCASE_EV_CORRECTION_2,
6927     PROPCASE_ORIENTATION_SENSOR,
6928     PROPCASE_SV_MARKET,
6929     PROPCASE_SVFIX,
6930     PROPCASE_TV,
6931     PROPCASE_HANDLED_COUNT
6932 };
6933 
6934 // names for all enumerated propcases (not all appear in CHDK source)
6935 char* prop_names[PROPCASE_HANDLED_COUNT] =
6936 {
6937     "PROPCASE_AFSTEP",
6938     "PROPCASE_FOCUS_STATE",
6939     "PROPCASE_AV",
6940     "PROPCASE_BV",
6941     "PROPCASE_DELTA_DIGITALGAIN",
6942     "PROPCASE_DELTA_SV",
6943     "PROPCASE_DELTA_ND",
6944     "PROPCASE_EV_CORRECTION_2",
6945     "PROPCASE_ORIENTATION_SENSOR",
6946     "PROPCASE_SV_MARKET",
6947     "PROPCASE_SVFIX",
6948     "PROPCASE_TV",
6949 };
6950 
6951 // for sig matching
6952 string_sig prop_sigs[] =
6953 {
6954     { 1, (char*)PROPCASE_AFSTEP, "\n\rError : GetAFStepResult", 0},
6955     { 1, (char*)PROPCASE_FOCUS_STATE, "\n\rError : GetAFResult", 0},
6956     { 1, (char*)PROPCASE_AV, "\n\rError : GetAvResult", 0},
6957     { 1, (char*)PROPCASE_BV, "\n\rError : GetBvResult", 0},
6958     { 1, (char*)PROPCASE_DELTA_DIGITALGAIN, "\n\rError : GetDeltaDigitalResult", 0},
6959     { 1, (char*)PROPCASE_DELTA_SV, "\n\rError : GetDeltaGainResult", 0},
6960     { 1, (char*)PROPCASE_DELTA_ND, "\n\rError : GetDeltaNdResult", 0},
6961     { 1, (char*)PROPCASE_EV_CORRECTION_2, "\n\rError : GetRealExposureCompensationResult", 0},
6962     { 1, (char*)PROPCASE_ORIENTATION_SENSOR, "\n\rError : GetRotationAngleResult", 0},
6963     { 1, (char*)PROPCASE_SV_MARKET, "\n\rError : GetSvResult", 0},
6964     { 1, (char*)PROPCASE_SVFIX, "\n\rError : GetSvFixResult", 0},
6965     { 1, (char*)PROPCASE_TV, "\n\rError : GetTvResult", 0},
6966     {-1, 0, 0}
6967 };
6968 
6969 typedef struct {
6970     int     num;    // internal id from enum
6971     int     id;     // propcase id, as found
6972     int     use;    // 0: informational only; 1: use for propset guess AND print as #define; 2: use for propset guess
6973 
6974     int     id_ps2; // id in propset 2
6975     int     id_ps3; // id in propset 3
6976     int     id_ps4; // id in propset 4
6977     int     id_ps5; // id in propset 5
6978     int     id_ps6; // id in propset 6
6979     int     id_ps7; // id in propset 7
6980     int     id_ps8; // id in propset 8
6981     int     id_ps9; // id in propset 9
6982     int     id_ps10;// id in propset 10
6983     int     id_ps11;// id in propset 11
6984     int     id_ps12;// id in propset 12
6985     int     id_ps13;// id in propset 13
6986 } known_prop_struct;
6987 
6988 
6989 #define KNOWN_PROPSET_COUNT 13
6990 
6991 known_prop_struct knownprops[PROPCASE_HANDLED_COUNT] =
6992 {   // enum                        id  u ps2 ps3 ps4 ps5 ps6 ps7 ps8 ps9 ps10 ps11 ps12 ps13
6993     {PROPCASE_AFSTEP             , -1, 0,  0,  0,  0,  0,  0,  0,  0,  0,   0,  13,  13,  13},
6994     {PROPCASE_FOCUS_STATE        , -1, 1, 18, 18, 18, 18, 18, 18, 18, 18,  18,  18,  18,  18},
6995     {PROPCASE_AV                 , -1, 1, 23, 23, 23, 23, 23, 23, 23, 23,  23,  23,  23,  23},
6996     {PROPCASE_BV                 , -1, 1, 34, 34, 34, 34, 34, 38, 35, 38,  40,  40,  40,  40},
6997     {PROPCASE_DELTA_DIGITALGAIN  , -1, 0,  0,  0,  0,  0,  0,  0,  0,  0,   0,  85,  85,  84},
6998     {PROPCASE_DELTA_SV           , -1, 1, 79, 79, 79, 79, 79, 84, 81, 84,  86,  87,  87,  86},
6999     {PROPCASE_DELTA_ND           , -1, 0,  0,  0,  0,  0,  0,  0,  0,  0,   0,  88,  88,  87},
7000     {PROPCASE_EV_CORRECTION_2    , -1, 1,207,209,211,211,210,216,213,216, 218, 219, 220, 218},
7001     {PROPCASE_ORIENTATION_SENSOR , -1, 1,219,221,223,223,222,228,225,228, 230, 231, 232, 230},
7002     {PROPCASE_SV_MARKET          , -1, 1,246,248,250,250,249,255,252,255, 257, 259, 260, 258},
7003     {PROPCASE_SVFIX              , -1, 0,  0,  0,  0,  0,  0,  0,  0,  0,   0, 260,   0, 259},
7004     {PROPCASE_TV                 , -1, 1,262,264,266,266,265,272,269,272, 274, 276, 277, 275},
7005 };
7006 
7007 static uintptr_t curr_prop_name;
7008 
7009 void add_prop_hit(int id, uintptr_t name)
7010 {
7011     knownprops[name].id = (int)id;
7012 }
7013 
7014 // string ref follows GetPropertyCase call
7015 int match_propsig1a(firmware *fw, int k, uint32_t sadr, __attribute__ ((unused))uint32_t offset)
7016 {
7017     if (isADR_PC_cond(fw,k) || isLDR_PC_cond(fw,k))   // LDR or ADR ?
7018     {
7019         uint32_t padr;
7020         if (isLDR_PC_cond(fw,k)) // LDR ?
7021             padr = LDR2val(fw,k);
7022         else
7023             padr = ADR2adr(fw,k);
7024         if (padr == sadr)
7025         {
7026             int j1 = find_inst_rev(fw, isBL, k-1, 16);
7027             if (j1 > 0)
7028             {
7029                 int j = get_saved_sig(fw,"GetPropertyCase");
7030                 if (j < 0)
7031                 {
7032                     return 0;
7033                 }
7034                 uint32_t fadr = func_names[j].val;
7035                 if (followBranch2(fw, idx2adr(fw,j1), 0x01000001) == fadr)
7036                 {
7037                     // GetPropertyCase call, ID is in r0
7038                     j = 0;
7039                 }
7040                 else
7041                 {
7042                     // get_prop_with_semaphore call, ID is in r1
7043                     j = 1;
7044                 }
7045                 int j2;
7046                 uint32_t a = 0;
7047                 for (j2=j1;j2>j1-8;j2--)
7048                 {
7049                     // ID is either an immediate (MOV) or two immediates added (MOV+ADD)
7050                     // larger IDs sometimes use LDR
7051                     if (a==0 && isLDR_PC(fw,j2) && fwRd(fw,j2)==j)
7052                     {
7053                         a = LDR2val(fw,j2);
7054                         if (a < 1000)
7055                         {
7056                             add_prop_hit(a, curr_prop_name);
7057                             return 1;
7058                         }
7059                     }
7060                     if (isADD(fw,j2) && fwRd(fw,j2)==j)
7061                     {
7062                         j = fwRn(fw, j2); // change the watched register on-the-fly
7063                         a += ALUop2a(fw, j2);
7064                     }
7065                     if (isMOV_immed(fw,j2) && fwRd(fw,j2)==j)
7066                     {
7067                         a += ALUop2a(fw, j2);
7068                         if (a < 1000)
7069                         {
7070                             add_prop_hit(a, curr_prop_name);
7071                             return 1;
7072                         }
7073                         break;
7074                     }
7075                 }
7076             }
7077         }
7078     }
7079     return 0;
7080 }
7081 int match_propsig1(firmware *fw, string_sig *sig, int j)
7082 {
7083     return search_fw(fw, match_propsig1a, idx2adr(fw,j), sig->offset, 1);
7084 }
7085 
7086 // Call processing function based on type
7087 int find_strsig2(firmware *fw, string_sig *sig)
7088 {
7089     switch (sig->type)
7090     {
7091     case 1:     return fw_string_process(fw, sig, match_propsig1, 1);
7092     }
7093 
7094     return 0;
7095 }
7096 
7097 void find_prop_matches(firmware *fw)
7098 {
7099     int i;
7100 
7101     for (i = 0; prop_sigs[i].type > -1; i++)
7102     {
7103         curr_prop_name = (uintptr_t)prop_sigs[i].name; // name (enum) has to be passed via a global
7104         find_strsig2(fw, &prop_sigs[i]);
7105     }
7106 
7107 }
7108 
7109 void find_propset(firmware *fw)
7110 {
7111     uint32_t used=0;
7112     uint32_t hits[KNOWN_PROPSET_COUNT];
7113 
7114     memset(hits, 0, KNOWN_PROPSET_COUNT*sizeof(uint32_t));
7115 
7116     find_prop_matches(fw);
7117 
7118     bprintf("\n// Known propcases\n");
7119 
7120     uint32_t n;
7121     for (n=0; n<PROPCASE_HANDLED_COUNT; n++)
7122     {
7123         used += knownprops[n].use>0?1:0;
7124         if (knownprops[n].id >= 0)
7125         {
7126             if (knownprops[n].use)
7127             {
7128                 if (knownprops[n].id == knownprops[n].id_ps2) hits[2-1] += 1;
7129                 if (knownprops[n].id == knownprops[n].id_ps3) hits[3-1] += 1;
7130                 if (knownprops[n].id == knownprops[n].id_ps4) hits[4-1] += 1;
7131                 if (knownprops[n].id == knownprops[n].id_ps5) hits[5-1] += 1;
7132                 if (knownprops[n].id == knownprops[n].id_ps6) hits[6-1] += 1;
7133                 if (knownprops[n].id == knownprops[n].id_ps7) hits[7-1] += 1;
7134                 if (knownprops[n].id == knownprops[n].id_ps8) hits[8-1] += 1;
7135                 if (knownprops[n].id == knownprops[n].id_ps9) hits[9-1] += 1;
7136                 if (knownprops[n].id == knownprops[n].id_ps10) hits[10-1] += 1;
7137                 if (knownprops[n].id == knownprops[n].id_ps11) hits[11-1] += 1;
7138                 if (knownprops[n].id == knownprops[n].id_ps12) hits[12-1] += 1;
7139                 if (knownprops[n].id == knownprops[n].id_ps13) hits[13-1] += 1;
7140             }
7141             if (knownprops[n].use == 1)
7142             {
7143                 bprintf("// #define %s %i\n", prop_names[n], knownprops[n].id);
7144             }
7145             else
7146             {
7147                 // propcases not used by CHDK, name may be made up
7148                 bprintf("// //      %s %i\n", prop_names[n], knownprops[n].id);
7149             }
7150         }
7151         else
7152         {
7153             bprintf("//         %s not found\n", prop_names[n]);
7154         }
7155     }
7156     bprintf("// Guessed propset: ");
7157     int m = 0;
7158     uint32_t fmax = 0;
7159     int okay = 0;
7160     for (n=1; n<KNOWN_PROPSET_COUNT; n++)
7161     {
7162         if (hits[n] == used)
7163         {
7164             if (m) bprintf(", ");
7165             bprintf("%i", n+1);
7166             if (fw->sv->propset == n+1) okay = 1; // if the propset equals to (one of) the complete propset matches
7167             m += 1;
7168         }
7169         if (hits[n] > fmax) fmax = hits[n];
7170     }
7171     if (m == 0)
7172     {
7173         bprintf("uncertain (%i of %u match), closest to ",fmax,used);
7174         for (n=1; n<KNOWN_PROPSET_COUNT; n++)
7175         {
7176             if (hits[n] == fmax)
7177             {
7178                 if (m) bprintf(", ");
7179                 bprintf("%i", n+1);
7180                 if (fw->sv->propset == n+1) okay = 1; // if the propset equals to (one of) the most complete propset matches
7181                 m += 1;
7182             }
7183         }
7184     }
7185     bprintf("\n");
7186     if (!okay && fw->sv->propset>0)
7187     {
7188         // only shown when there's a clear mismatch
7189         bprintf("// Port's propset (%i) may be set incorrectly\n", fw->sv->propset);
7190     }
7191 }
7192 
7193 // Search for things
7194 void find_other_vals(firmware *fw)
7195 {
7196     out_hdr = 1;
7197     add_blankline();
7198 
7199     bprintf("// Misc stuff\n");
7200 
7201     if (!search_fw_bytes(fw, find_ctypes))
7202     {
7203         bprintf("//DEF(ctypes, *** Not Found ***)\n");
7204     }
7205 
7206     add_blankline();
7207     print_exmem_types(fw);
7208     find_task_related_info(fw);
7209     find_leds(fw);
7210 
7211     // Look for nrflag (for capt_seq.c)
7212     int found = 0;
7213     if (fw->dryos_ver >= 45)
7214     {
7215         found = search_saved_sig(fw, "NR_SetDarkSubType", match_nrflag, 0, 0, 1);
7216     }
7217     if (!found)
7218     {
7219         search_saved_sig(fw, "NR_GetDarkSubType", match_nrflag2, 0, 0, 20);
7220     }
7221 }
7222 
7223 //------------------------------------------------------------------------------------------------------------
7224 
7225 void print_kval(firmware *fw, uint32_t tadr, int tsiz, int tlen, uint32_t ev, const char *name, char *sfx)
7226 {
7227     int tidx = adr2idx(fw,tadr);
7228     int k, kval = 0;
7229     for (k=0; k<tlen; k+=tsiz)
7230     {
7231         if (fw->buf[tidx+k+1] == ev)
7232         {
7233             kval = fw->buf[tidx+k];
7234             tadr = idx2adr(fw,tidx+k);
7235             break;
7236         }
7237     }
7238     if (kval > 0)
7239     {
7240         char fn[100], rn[100];
7241         strcpy(fn,name); strcat(fn,sfx);
7242         strcpy(rn,name); strcat(rn,"_IDX");
7243 
7244         int r = (kval >> 5) & 7;
7245         uint32_t b = (1 << (kval & 0x1F));
7246         int i = (kval >> 16) & 1;
7247 
7248         bprintf("//#define %-20s0x%08x // Found @0x%08x, levent 0x%x%s\n",fn,b,tadr,ev,i?" (non-inverted logic)":"");
7249         bprintf("//#define %-20s%d\n",rn,r);
7250     }
7251 }
7252 
7253 void print_physw_raw_vals(firmware *fw, uint32_t tadr, int tsiz, int tlen)
7254 {
7255     int tidx = adr2idx(fw,tadr);
7256     int k, kval = 0;
7257     uint32_t ev;
7258     FILE *out_fp = fopen("physw_bits.txt", "w");
7259     if (out_fp == NULL) return;
7260 
7261     for (k=0; k<tlen; k+=tsiz)
7262     {
7263         ev = fw->buf[tidx+k+1];
7264         kval = fw->buf[tidx+k];
7265         tadr = idx2adr(fw,tidx+k);
7266         if (kval > 0)
7267         {
7268 
7269             int r = (kval >> 5) & 7;
7270             uint32_t b = (1 << (kval & 0x1F));
7271             int i = (kval >> 16) & 1;
7272 
7273             fprintf(out_fp, "levent 0x%08x, 0x%08x, index %d%s\n", ev, b, r, i?" (non-inverted logic)":"");
7274         }
7275     }
7276     fclose(out_fp);
7277 }
7278 
7279 typedef struct {
7280     int         reg;
7281     uint32_t    bits;
7282     char        nm[32];
7283     uint32_t    fadr;
7284     uint32_t    ev;
7285     int         inv;
7286 } kinfo;
7287 
7288 int     kmask[3];
7289 kinfo   key_info[100];
7290 int     kcount = 0;
7291 uint32_t kshutter_min_bits = 0xFFFFFFFF;
7292 
7293 void add_kinfo(int r, uint32_t b, const char *nm, uint32_t adr, uint32_t ev, int inv)
7294 {
7295     key_info[kcount].reg = r;
7296     key_info[kcount].bits = b;
7297     strcpy(key_info[kcount].nm, nm);
7298     key_info[kcount].fadr = adr;
7299     key_info[kcount].ev = ev;
7300     key_info[kcount].inv = inv;
7301     kcount++;
7302     kmask[r] |= b;
7303     if ((ev <= 1) && (b < kshutter_min_bits)) kshutter_min_bits = b;
7304 }
7305 
7306 uint32_t add_kmval(firmware *fw, uint32_t tadr, int tsiz, int tlen, uint32_t ev, const char *name, uint32_t xtra)
7307 {
7308     int tidx = adr2idx(fw,tadr);
7309     int r, k, kval = 0;
7310     uint32_t b = 0;
7311     int inv = 0;
7312     for (k=0; k<tlen; k+=tsiz)
7313     {
7314         if (fw->buf[tidx+k+1] == ev)
7315         {
7316             kval = fw->buf[tidx+k];
7317             tadr = idx2adr(fw,tidx+k);
7318             break;
7319         }
7320     }
7321     if (kval > 0)
7322     {
7323         r = (kval >> 5) & 7;
7324         b = (1 << (kval & 0x1F));
7325         inv = ((kval&0xff0000)==0x10000)?0:1;
7326 
7327         add_kinfo(r,b|xtra,name,tadr,ev,inv);
7328     }
7329 
7330     return b;
7331 }
7332 
7333 int kinfo_compare(const kinfo *p1, const kinfo *p2)
7334 {
7335     if (p1->reg > p2->reg)
7336     {
7337         return 1;
7338     }
7339     else if (p1->reg < p2->reg)
7340     {
7341         return -1;
7342     }
7343     if ((p1->ev <= 1) && (p2->ev <= 1))    // output shutter entries in reverse order
7344     {
7345         if (p1->bits > p2->bits)
7346         {
7347             return -1;
7348         }
7349         else if (p1->bits < p2->bits)
7350         {
7351             return 1;
7352         }
7353     }
7354     // if one entry is shutter then compare to min shutter bits
7355     if (p1->ev <= 1)
7356     {
7357         if (kshutter_min_bits > p2->bits)
7358         {
7359             return 1;
7360         }
7361         else if (kshutter_min_bits < p2->bits)
7362         {
7363             return -1;
7364         }
7365     }
7366     if (p2->ev <= 1)
7367     {
7368         if (p1->bits > kshutter_min_bits)
7369         {
7370             return 1;
7371         }
7372         else if (p1->bits < kshutter_min_bits)
7373         {
7374             return -1;
7375         }
7376     }
7377     if (p1->bits > p2->bits)
7378     {
7379         return 1;
7380     }
7381     else if (p1->bits < p2->bits)
7382     {
7383         return -1;
7384     }
7385 
7386     return 0;
7387 }
7388 
7389 void print_kmvals()
7390 {
7391     qsort(key_info, kcount, sizeof(kinfo), (void*)kinfo_compare);
7392 
7393     bprintf("//static KeyMap keymap[] = {\n");
7394 
7395     int k;
7396     for (k=0; k<kcount; k++)
7397     {
7398         bprintf("//    { %d, %-20s,0x%08x }, // Found @0x%08x, levent 0x%02x%s\n",key_info[k].reg,key_info[k].nm,key_info[k].bits,key_info[k].fadr,key_info[k].ev,(key_info[k].inv==0)?"":" (uses inverted logic in physw_status)");
7399     }
7400 
7401     bprintf("//    { 0, 0, 0 }\n//};\n");
7402 }
7403 
7404 int match_GetSDProtect(firmware *fw, int k, __attribute__ ((unused))int v)
7405 {
7406     if (isB(fw,k))    // B
7407     {
7408         k = idxFollowBranch(fw,k,1);
7409         if (isLDR_PC(fw,k))
7410         {
7411             return LDR2val(fw,k);
7412         }
7413     }
7414 
7415     return 0;
7416 }
7417 
7418 void find_key_vals(firmware *fw)
7419 {
7420     int k,k1;
7421 
7422     out_hdr = 1;
7423     add_blankline();
7424 
7425     // find 'SD_READONLY_FLAG'
7426     uint32_t tadr = search_saved_sig(fw, "GetSDProtect", match_GetSDProtect, 0, 1, 1);
7427     if (tadr == 0)
7428     {
7429         k = find_str_ref(fw,"SD Not Exist\n");
7430         if (k >= 0)
7431         {
7432             for (k1=k-1; k1>k-5; k1--)
7433             {
7434                 if (isBL(fw,k1))    // BL
7435                 {
7436                     uint32_t fadr = followBranch(fw,idx2adr(fw,k1),0x01000001);
7437                     int k2 = adr2idx(fw,fadr);
7438                     if (isLDR_PC(fw,k2))
7439                     {
7440                         tadr = LDR2val(fw,k2);
7441                     }
7442                 }
7443             }
7444         }
7445     }
7446     if (tadr != 0)
7447     {
7448         uint32_t tsiz = 2;
7449         if (fw->buf[adr2idx(fw,tadr)+2] == 0) tsiz = 3;
7450 
7451         uint32_t madr = fw->base + (fw->size*4-4);
7452         for (k=0; k<(int)(tadr-fw->base)/4; k++)
7453         {
7454             if (isLDR_PC(fw,k))
7455             {
7456                 uint32_t adr = LDR2val(fw,k);
7457                 if ((adr > tadr) && (adr < madr))
7458                 {
7459                     madr = adr;
7460                 }
7461             }
7462         }
7463         uint32_t tlen = (madr - tadr) / 4;
7464         if (tsiz == 2)
7465         {
7466             k1 = adr2idx(fw,tadr);
7467             for (k=0; k<(int)tlen/3; k+=3)
7468             {
7469                 if ((fw->buf[k1+k+1] == 0xFFFFFFFF) && (fw->buf[k1+k+4] == 0xFFFFFFFF))
7470                 {
7471                     tsiz = 3;
7472                     break;
7473                 }
7474             }
7475         }
7476         if (tlen > 50*tsiz) tlen = 50*tsiz;
7477 
7478 #ifdef LIST_PHYSW_TABLE
7479         // output all physw events from the table if enabled
7480         print_physw_raw_vals(fw, tadr, tsiz, tlen);
7481 #endif
7482         bprintf("// Bitmap masks and physw_status index values for SD_READONLY and USB power flags (for kbd.c).\n");
7483         if (fw->dryos_ver >= 58)
7484         {
7485             // Event ID's have changed again in DryOS 58 **********
7486             print_kval(fw,tadr,tsiz,tlen,0x30A,"SD_READONLY","_FLAG");
7487             print_kval(fw,tadr,tsiz,tlen,0x302,"USB","_MASK");
7488             print_kval(fw,tadr,tsiz,tlen,0x305,"BATTCOVER","_FLAG");
7489             print_kval(fw,tadr,tsiz,tlen,0x304,"HOTSHOE","_FLAG");
7490             print_kval(fw,tadr,tsiz,tlen,0x300,"ANALOG_AV","_FLAG");
7491         }
7492         else if (fw->dryos_ver >= 49)
7493         {
7494             // Event ID's have changed in DryOS R49 **********
7495             print_kval(fw,tadr,tsiz,tlen,0x20A,"SD_READONLY","_FLAG");
7496             print_kval(fw,tadr,tsiz,tlen,0x202,"USB","_MASK");
7497             print_kval(fw,tadr,tsiz,tlen,0x205,"BATTCOVER","_FLAG");
7498             print_kval(fw,tadr,tsiz,tlen,0x204,"HOTSHOE","_FLAG");
7499             print_kval(fw,tadr,tsiz,tlen,0x200,"ANALOG_AV","_FLAG");
7500         }
7501         else
7502         {
7503             print_kval(fw,tadr,tsiz,tlen,0x90A,"SD_READONLY","_FLAG");
7504             print_kval(fw,tadr,tsiz,tlen,0x902,"USB","_MASK");
7505             print_kval(fw,tadr,tsiz,tlen,0x905,"BATTCOVER","_FLAG");
7506             print_kval(fw,tadr,tsiz,tlen,0x904,"HOTSHOE","_FLAG");
7507             print_kval(fw,tadr,tsiz,tlen,0x900,"ANALOG_AV","_FLAG");
7508         }
7509 
7510         uint32_t key_half = add_kmval(fw,tadr,tsiz,tlen,0,"KEY_SHOOT_HALF",0);
7511         add_kmval(fw,tadr,tsiz,tlen,1,"KEY_SHOOT_FULL",key_half);
7512         add_kmval(fw,tadr,tsiz,tlen,1,"KEY_SHOOT_FULL_ONLY",0);
7513 
7514         if (fw->dryos_ver == 52)  // unclear if this applies any other ver
7515         {
7516             add_kmval(fw,tadr,tsiz,tlen,3,"KEY_ZOOM_IN",0);
7517             add_kmval(fw,tadr,tsiz,tlen,4,"KEY_ZOOM_OUT",0);
7518             add_kmval(fw,tadr,tsiz,tlen,6,"KEY_UP",0);
7519             add_kmval(fw,tadr,tsiz,tlen,7,"KEY_DOWN",0);
7520             add_kmval(fw,tadr,tsiz,tlen,8,"KEY_LEFT",0);
7521             add_kmval(fw,tadr,tsiz,tlen,9,"KEY_RIGHT",0);
7522             add_kmval(fw,tadr,tsiz,tlen,0xA,"KEY_SET",0);
7523             add_kmval(fw,tadr,tsiz,tlen,0xB,"KEY_MENU",0);
7524             add_kmval(fw,tadr,tsiz,tlen,0xC,"KEY_DISPLAY",0);
7525             add_kmval(fw,tadr,tsiz,tlen,0x12,"KEY_HELP",0);
7526             add_kmval(fw,tadr,tsiz,tlen,0x19,"KEY_ERASE",0);
7527             add_kmval(fw,tadr,tsiz,tlen,2,"KEY_VIDEO",0);
7528         }
7529         else if (fw->dryos_ver < 54)
7530         {
7531             add_kmval(fw,tadr,tsiz,tlen,2,"KEY_ZOOM_IN",0);
7532             add_kmval(fw,tadr,tsiz,tlen,3,"KEY_ZOOM_OUT",0);
7533             add_kmval(fw,tadr,tsiz,tlen,4,"KEY_UP",0);
7534             add_kmval(fw,tadr,tsiz,tlen,5,"KEY_DOWN",0);
7535             add_kmval(fw,tadr,tsiz,tlen,6,"KEY_LEFT",0);
7536             add_kmval(fw,tadr,tsiz,tlen,7,"KEY_RIGHT",0);
7537             add_kmval(fw,tadr,tsiz,tlen,8,"KEY_SET",0);
7538             add_kmval(fw,tadr,tsiz,tlen,9,"KEY_MENU",0);
7539             add_kmval(fw,tadr,tsiz,tlen,0xA,"KEY_DISPLAY",0);
7540         }
7541         else if (fw->dryos_ver < 55)
7542         {
7543             add_kmval(fw,tadr,tsiz,tlen,3,"KEY_ZOOM_IN",0);
7544             add_kmval(fw,tadr,tsiz,tlen,4,"KEY_ZOOM_OUT",0);
7545             add_kmval(fw,tadr,tsiz,tlen,6,"KEY_UP",0);
7546             add_kmval(fw,tadr,tsiz,tlen,7,"KEY_DOWN",0);
7547             add_kmval(fw,tadr,tsiz,tlen,8,"KEY_LEFT",0);
7548             add_kmval(fw,tadr,tsiz,tlen,9,"KEY_RIGHT",0);
7549             add_kmval(fw,tadr,tsiz,tlen,0xA,"KEY_SET",0);
7550             add_kmval(fw,tadr,tsiz,tlen,0xE,"KEY_MENU",0);
7551             add_kmval(fw,tadr,tsiz,tlen,2,"KEY_VIDEO",0);
7552             add_kmval(fw,tadr,tsiz,tlen,0xD,"KEY_HELP",0);
7553             //add_kmval(fw,tadr,tsiz,tlen,?,"KEY_DISPLAY",0);
7554         }
7555         else
7556         {
7557             add_kmval(fw,tadr,tsiz,tlen,3,"KEY_ZOOM_IN",0);
7558             add_kmval(fw,tadr,tsiz,tlen,4,"KEY_ZOOM_OUT",0);
7559             add_kmval(fw,tadr,tsiz,tlen,6,"KEY_UP",0);
7560             add_kmval(fw,tadr,tsiz,tlen,7,"KEY_DOWN",0);
7561             add_kmval(fw,tadr,tsiz,tlen,8,"KEY_LEFT",0);
7562             add_kmval(fw,tadr,tsiz,tlen,9,"KEY_RIGHT",0);
7563             add_kmval(fw,tadr,tsiz,tlen,0xA,"KEY_SET",0);
7564             add_kmval(fw,tadr,tsiz,tlen,0x14,"KEY_MENU",0);
7565             add_kmval(fw,tadr,tsiz,tlen,2,"KEY_VIDEO",0);
7566             add_kmval(fw,tadr,tsiz,tlen,0xD,"KEY_HELP",0);
7567             //add_kmval(fw,tadr,tsiz,tlen,?,"KEY_DISPLAY",0);
7568         }
7569         if (fw->dryos_ver <= 47)
7570         {
7571             add_kmval(fw,tadr,tsiz,tlen,0x601,"KEY_PLAYBACK",0);
7572             add_kmval(fw,tadr,tsiz,tlen,0x600,"KEY_POWER",0);
7573             add_kmval(fw,tadr,tsiz,tlen,0x12,"KEY_VIDEO",0);
7574         }
7575         else
7576         {
7577             add_kmval(fw,tadr,tsiz,tlen,0x101,"KEY_PLAYBACK",0);
7578             add_kmval(fw,tadr,tsiz,tlen,0x100,"KEY_POWER",0);
7579             if (fw->dryos_ver == 49)
7580             {
7581                 add_kmval(fw,tadr,tsiz,tlen,0x19,"KEY_VIDEO",0);
7582             }
7583             else if(fw->dryos_ver == 50)
7584             {
7585                 add_kmval(fw,tadr,tsiz,tlen,0x1A,"KEY_VIDEO",0);
7586                 add_kmval(fw,tadr,tsiz,tlen,0x14,"KEY_HELP",0);
7587             }
7588         }
7589 
7590         bprintf("\n// Keymap values for kbd.c. Additional keys may be present, only common values included here.\n");
7591         print_kmvals();
7592     }
7593 }
7594 
7595 //------------------------------------------------------------------------------------------------------------
7596 
7597 uint32_t nadr;
7598 uint32_t eadr;
7599 
7600 int get_eventproc_val(firmware *fw, int k)
7601 {
7602     if (isADR_PC(fw,k) && (fwRd(fw,k) == 0))
7603         nadr = ADR2adr(fw,k);
7604     else if (isADR_PC(fw,k) && (fwRd(fw,k) == 1))
7605         eadr = ADR2adr(fw,k);
7606     else if (isLDR_PC(fw,k) && (fwRd(fw,k) == 0))
7607         nadr = LDR2val(fw,k);
7608     else if (isLDR_PC(fw,k) && (fwRd(fw,k) == 1))
7609         eadr = LDR2val(fw,k);
7610     else
7611         return 0;
7612     return 1;
7613 }
7614 
7615 void add_func_name(char *n, uint32_t eadr, char *suffix)
7616 {
7617     int k;
7618 
7619     char *s = n;
7620     if (suffix != 0)
7621     {
7622         s = malloc(strlen(n) + strlen(suffix) + 1);
7623         sprintf(s, "%s%s", n, suffix);
7624     }
7625 
7626     for (k=0; func_names[k].name != 0; k++)
7627     {
7628         if (strcmp(func_names[k].name, s) == 0)
7629         {
7630             if (func_names[k].val == 0)             // same name, no address
7631             {
7632                 func_names[k].val = eadr;
7633                 func_names[k].flags |= EV_MATCH;
7634                 if (s != n) free(s);
7635                 return;
7636             }
7637             else if (func_names[k].val == eadr)     // same name, same address
7638             {
7639                 if (s != n) free(s);
7640                 return;
7641             }
7642         }
7643     }
7644 
7645     func_names[next_func_entry].name = s;
7646     func_names[next_func_entry].flags = OPTIONAL|UNUSED;
7647     func_names[next_func_entry].val = eadr;
7648     next_func_entry++;
7649     func_names[next_func_entry].name = 0;
7650 }
7651 
7652 void add_func_name2(firmware *fw, uint32_t nadr, uint32_t eadr, char *suffix)
7653 {
7654     char *n = (char*)adr2ptr(fw,nadr);
7655     if (isB(fw,adr2idx(fw,eadr)))
7656     {
7657         char *s = malloc(strlen(n) + 3);
7658         sprintf(s,"j_%s",n);
7659         add_func_name(s, eadr, suffix);
7660         eadr = followBranch(fw,eadr,1);
7661     }
7662     add_func_name(n, eadr, suffix);
7663 }
7664 
7665 int match_eventproc(firmware *fw, int k, uint32_t fadr, __attribute__ ((unused))uint32_t v2)
7666 {
7667     if (isBorBL(fw,k))
7668     {
7669         uint32_t adr = followBranch(fw,idx2adr(fw,k),0x01000001);
7670         if (adr == fadr)
7671         {
7672             nadr = 0;
7673             eadr = 0;
7674             k--;
7675             if (get_eventproc_val(fw, k) == 0)
7676             {
7677                 int k1 = find_inst_rev(fw, isB, k, 500);
7678                 if (k1 >= 0)
7679                 {
7680                     k = k1 - 1;
7681                     get_eventproc_val(fw, k);
7682                 }
7683             }
7684             k--;
7685             if (get_eventproc_val(fw, k) == 0)
7686             {
7687                 int k1 = find_inst_rev(fw, isB, k, 500);
7688                 if (k1 >= 0)
7689                 {
7690                     k = k1 - 1;
7691                     get_eventproc_val(fw, k);
7692                 }
7693             }
7694             if ((nadr != 0) && (eadr != 0))
7695             {
7696                 add_func_name2(fw, nadr, eadr, "_FW");
7697             }
7698         }
7699     }
7700     return 0;
7701 }
7702 
7703 int match_registerproc2(firmware *fw, int k, uint32_t fadr, __attribute__ ((unused))uint32_t v2)
7704 {
7705     int j = k;
7706     if (isBorBL(fw,k))
7707     {
7708         uint32_t adr = followBranch(fw,idx2adr(fw,k),0x01000001);
7709         if (adr == fadr)
7710         {
7711             nadr = 0;
7712             eadr = 0;
7713             k--;
7714             if (get_eventproc_val(fw, k) == 0)
7715             {
7716                 int k1 = find_inst_rev(fw, isB, k, 500);
7717                 if (k1 >= 0)
7718                 {
7719                     k = k1 - 1;
7720                     get_eventproc_val(fw, k);
7721                 }
7722             }
7723             k--;
7724             if (get_eventproc_val(fw, k) == 0)
7725             {
7726                 int k1 = find_inst_rev(fw, isB, k, 500);
7727                 if (k1 >= 0)
7728                 {
7729                     k = k1 - 1;
7730                     get_eventproc_val(fw, k);
7731                 }
7732             }
7733             if ((nadr != 0) && (eadr != 0))
7734             {
7735                 add_func_name2(fw, nadr, eadr, "_FW");
7736             }
7737             else
7738             {
7739                 // find spec case (when used in a loop)
7740                 k = j;
7741                 int k1 = find_inst_rev(fw, isLDR_PC, k, 8);
7742                 if (k1 > 0)
7743                 {
7744                     uint32_t k2 = LDR2val(fw,k1);
7745                     if ((k2 > fw->base) && (k2 < (fw->base + fw->size*4 - 1)))
7746                     {
7747                         int k3 = k;
7748                         while (k3 > k-4)
7749                         {
7750                             if ( ((fwval(fw,k3) & 0xfff00ff0) == 0xe0800180) && // add rx, ry, rz, lsl #3
7751                                ((fwval(fw,k3) & 0x000f0000)>>16) == (unsigned)(fwRd(fw,k1)) ) // check register match
7752                             {
7753                                 // table confirmed, process it
7754                                 k1 = adr2idx(fw,k2);
7755                                 while (fwval(fw,k1) != 0)
7756                                 {
7757                                     add_func_name2(fw, fwval(fw,k1), fwval(fw,k1+1), "_FW");
7758                                     k1 += 2;
7759                                 }
7760                                 break;
7761                             }
7762                             k3--;
7763                         }
7764                     }
7765                 }
7766             }
7767         }
7768     }
7769     return 0;
7770 }
7771 
7772 int match_registerproc(firmware *fw, int k, uint32_t fadr, __attribute__ ((unused))uint32_t v2)
7773 {
7774     if (isB(fw,k+1) && isMOV_immed(fw,k) && (fwRd(fw,k) == 2))
7775     {
7776         uint32_t adr = followBranch(fw,idx2adr(fw,k+1),1);
7777         if (adr == fadr)
7778         {
7779             search_fw(fw, match_registerproc2, idx2adr(fw,k), 0, 2);
7780         }
7781     }
7782     return 0;
7783 }
7784 
7785 int match_registerlists(firmware *fw, int k, uint32_t fadr, __attribute__ ((unused))uint32_t v2)
7786 {
7787     if (isBorBL(fw,k+1) && isLDR_PC(fw,k) && (fwRd(fw,k) == 0))
7788     {
7789         uint32_t adr = followBranch2(fw,idx2adr(fw,k+1),0x01000001);
7790         if (adr == fadr)
7791         {
7792             int j = adr2idx(fw,LDR2val(fw,k));
7793             if (!idx_valid(fw,j))
7794             {
7795                 j = adr2idx(fw,LDR2val(fw,k) - fw->data_start + fw->data_init_start);
7796             }
7797             if (idx_valid(fw,j))
7798             {
7799                 while (fwval(fw,j) != 0)
7800                 {
7801                     add_func_name2(fw, fwval(fw,j), fwval(fw,j+1), "_FW");
7802                     j += 2;
7803                 }
7804             }
7805         }
7806     }
7807     else if (isBorBL(fw,k+1) && isLDMFD(fw,k) && isLDR_PC(fw,k-1) && (fwRd(fw,k-1) == 0))
7808     {
7809         uint32_t adr = followBranch2(fw,idx2adr(fw,k+1),0x01000001);
7810         if (adr == fadr)
7811         {
7812             int j = adr2idx(fw,LDR2val(fw,k-1));
7813             if (!idx_valid(fw,j))
7814             {
7815                 j = adr2idx(fw,LDR2val(fw,k-1) - fw->data_start + fw->data_init_start);
7816             }
7817             if (idx_valid(fw,j))
7818             {
7819                 while (fwval(fw,j) != 0)
7820                 {
7821                     add_func_name2(fw, fwval(fw,j), fwval(fw,j+1), "_FW");
7822                     j += 2;
7823                 }
7824             }
7825         }
7826     }
7827     return 0;
7828 }
7829 
7830 void find_eventprocs(firmware *fw)
7831 {
7832     int j = get_saved_sig(fw,"ExportToEventProcedure_FW");
7833     if (j >= 0)
7834     {
7835         uint32_t fadr = func_names[j].val;
7836         search_fw(fw, match_eventproc, fadr, 0, 1);
7837 
7838         if (isB(fw,adr2idx(fw,fadr)+2))
7839         {
7840             fadr = followBranch(fw, fadr+8, 1);
7841             add_func_name("RegisterEventProcedure", fadr, 0);
7842             search_fw(fw, match_registerproc, fadr, 0, 2);
7843         }
7844 
7845         j = get_saved_sig(fw,"SS.Create_FW");
7846         if (j >= 0)
7847         {
7848             j = adr2idx(fw,func_names[j].val);
7849             int offsets[] = { 1, 3, 7, 8 };
7850             int i;
7851             for (i=0; i<4; i++)
7852             {
7853                 if (isLDR_PC(fw,j+offsets[i]) && (fwRd(fw,j+offsets[i]) == 0) && isBL(fw,j+offsets[i]+1))
7854                 {
7855                     fadr = followBranch(fw,idx2adr(fw,j+offsets[i]+1),0x01000001);
7856                     search_fw(fw, match_registerlists, fadr, 0, 2);
7857                     break;
7858                 }
7859             }
7860         }
7861         else
7862         {
7863             // S5IS
7864             j = find_strptr_ref(fw,"ResetZoomLens");
7865             if (j >= 0)
7866             {
7867                 if (isBorBL(fw,j+1))
7868                 {
7869                     fadr = followBranch(fw,idx2adr(fw,j+1),0x01000001);
7870                     search_fw(fw, match_registerlists, fadr, 0, 2);
7871                 }
7872             }
7873         }
7874 
7875         j = get_saved_sig(fw,"TerminateAdjustmentSystem_FW");
7876         if (j >= 0)
7877         {
7878             j = adr2idx(fw,func_names[j].val);
7879             int k;
7880             for (k=j; k<j+8; k++)
7881             {
7882                 if (isBL(fw,k))
7883                 {
7884                     int k1 = adr2idx(fw,followBranch(fw,idx2adr(fw,k),0x01000001));
7885                     int k2;
7886                     for (k2=k1; k2<k1+20; k2++)
7887                     {
7888                         if (isLDR_PC(fw,k2) && (fwRd(fw,k2) == 0) && isLDMFD(fw,k2+1))
7889                         {
7890                             int k3 = adr2idx(fw, LDR2val(fw,k2) - fw->data_start + fw->data_init_start);
7891                             if (idx_valid(fw,k3))
7892                             {
7893                                 while (fwval(fw,k3) != 0)
7894                                 {
7895                                     add_func_name2(fw, fwval(fw,k3), fwval(fw,k3+1), "_FW");
7896                                     k3 += 2;
7897                                 }
7898                             }
7899                         }
7900                     }
7901                 }
7902             }
7903         }
7904     }
7905 }
7906 
7907 uint32_t findTaskAddress(firmware *fw, int k, int reg)
7908 {
7909     int o;
7910 
7911     for (o=-1; o>-7; o--)
7912     {
7913         if (isLDR_PC(fw,k+o) && (fwRd(fw,k+o) == reg))
7914         {
7915             uint32_t adr = LDR2val(fw,k+o);
7916             int i;
7917             for (i=o+1; i<0; i++)
7918             {
7919                 if (fwval(fw,k+i) == (0xE5900000 | (reg << 12) | (reg << 16)))    // LDR Rx,[Rx]
7920                 {
7921                     adr = fwval(fw,adr2idx(fw,adr));
7922                 }
7923             }
7924             return adr;
7925         }
7926         else if (isADR_PC(fw,k+o) && (fwRd(fw,k+o) == reg))
7927         {
7928             return(ADR2adr(fw,k+o));
7929         }
7930     }
7931 
7932     return 0;
7933 }
7934 
7935 int match_createtask(firmware *fw, int k, uint32_t fadr, __attribute__ ((unused))uint32_t v2)
7936 {
7937     // cams with code copied to RAM: use RAM address
7938     k = idxcorr(fw, k);
7939     if (isBorBL(fw,k))
7940     {
7941         uint32_t adr = followBranch2(fw,idx2adr(fw,k),0x01000001);
7942         if (adr == fadr)
7943         {
7944             fadr = findTaskAddress(fw, k, 3);
7945             if (fadr != 0)
7946             {
7947                 uint32_t sadr = findTaskAddress(fw, k, 0);
7948                 if (sadr != 0)
7949                 {
7950                     char *s = adr2ptr(fw,sadr);
7951                     char *nm = malloc(strlen(s)+6);
7952                     sprintf(nm,"task_%s",s);
7953                     add_func_name(nm, fadr, 0);
7954                 }
7955             }
7956         }
7957     }
7958 
7959     return 0;
7960 }
7961 
7962 void find_tasks(firmware *fw)
7963 {
7964     int k = get_saved_sig(fw,"CreateTask");
7965     if (k >= 0)
7966     {
7967         search_fw(fw, match_createtask, func_names[k].val, 0, 7);
7968     }
7969     k = get_saved_sig(fw,"CreateTaskStrictly");
7970     if (k >= 0)
7971     {
7972         search_fw(fw, match_createtask, func_names[k].val, 0, 7);
7973     }
7974     if (fw->dryos_ver >= 59)
7975     {
7976         k = get_saved_sig(fw,"CreateTaskStrictly_alt"); // r59+
7977         if (k >= 0)
7978         {
7979             search_fw(fw, match_createtask, func_names[k].val, 0, 7);
7980         }
7981     }
7982 }
7983 
7984 void find_builddate(firmware *fw)
7985 {
7986     int j = get_saved_sig(fw,"GetBuildDate_FW");
7987     if (j >= 0)
7988     {
7989         int idx = adr2idx(fw, func_names[j].val);
7990         uint32_t adr = ADR2adr(fw, idx);
7991         idx = adr2idx(fw, adr);
7992         fw->fw_build_date = (char*)&fw->buf[idx];
7993     }
7994     else
7995         fw->fw_build_date = 0;
7996 
7997     j = get_saved_sig(fw,"GetBuildTime_FW");
7998     if (j >= 0)
7999     {
8000         int idx = adr2idx(fw, func_names[j].val);
8001         uint32_t adr = ADR2adr(fw, idx);
8002         idx = adr2idx(fw, adr);
8003         fw->fw_build_time = (char*)&fw->buf[idx];
8004     }
8005     else
8006         fw->fw_build_time = 0;
8007 }
8008 
8009 int save_ptp_handler_func(uint32_t op,uint32_t handler) {
8010     if((op >= 0x9000 && op < 0x10000) || (op >= 0x1000 && op < 0x2000)) {
8011         char *buf=malloc(64);
8012         const char *nm=get_ptp_op_name(op);
8013         if(nm) {
8014             sprintf(buf,"handle_%s",nm);
8015         } else {
8016             sprintf(buf,"handle_PTP_OC_0x%04x",op);
8017         }
8018         // TODO Canon sometimes uses the same handler for multiple opcodes
8019         add_func_name(buf,handler,NULL);
8020     } else {
8021         return 0;
8022     }
8023     return 1;
8024 }
8025 
8026 int find_ptp_handler_imm(firmware *fw, int k)
8027 {
8028     int o;
8029 
8030     uint32_t op=0;
8031     uint32_t handler=0;
8032 
8033 //    fprintf(stderr,"find_ptp_handler_imm 0x%x\n",idx2adr(fw,k));
8034     for (o=-1; o>-7; o--)
8035     {
8036         if (isLDR_PC(fw,k+o))
8037         {
8038             if(fwRd(fw,k+o) == 0)
8039             {
8040                 op = LDR2val(fw,k+o);
8041             }
8042             else if(fwRd(fw,k+o) == 1){
8043                 handler = LDR2val(fw,k+o);
8044             }
8045         }
8046         // only expect handler to come from adr
8047         else if (isADR_PC(fw,k+o) && (fwRd(fw,k+o) == 1))
8048         {
8049             handler=ADR2adr(fw,k+o);
8050         }
8051         // TODO op can also be genrated by shifts and bit operations
8052         if(op && handler) {
8053 //            fprintf(stderr,"find_ptp_handler_imm found 0x%x 0x%x\n",op,handler);
8054             return save_ptp_handler_func(op,handler);
8055         }
8056     }
8057 //    fprintf(stderr,"find_ptp_handler_imm not found\n");
8058     return 0;
8059 }
8060 
8061 int match_ptp_handlers(firmware *fw, int k, uint32_t fadr, __attribute__ ((unused))uint32_t v2)
8062 {
8063     // check for table of opcode, func ptr (word aligned), ...
8064     if(fwval(fw,k) == 0x1004
8065         && fwval(fw,k+2) == 0x1005
8066         && fwval(fw,k+4) == 0x1006
8067         && fwval(fw,k+1) > fw->base && !(fwval(fw,k+1) & 0x3)
8068         && fwval(fw,k+3) > fw->base && !(fwval(fw,k+1) & 0x3)
8069         && fwval(fw,k+5) > fw->base && !(fwval(fw,k+1) & 0x3))
8070     {
8071         // TODO canon firmware has count in loop that calls add_ptp_handler,
8072         // but for simplicity just checking for valid opcode with hardcoded max
8073         int i;
8074         for(i=0; i<64; i++) {
8075             uint32_t op=fwval(fw,k+i*2);
8076             uint32_t handler=fwval(fw,k+i*2+1);
8077             // fails on op out of range
8078             if(!save_ptp_handler_func(op,handler)) {
8079                 break;
8080             }
8081         }
8082         return 0;
8083     }
8084     // otherwise, check for calls
8085     // cams with code copied to RAM: use RAM address
8086     k = idxcorr(fw, k);
8087     if (!isBorBL(fw,k))
8088     {
8089         return 0;
8090     }
8091     uint32_t adr = followBranch2(fw,idx2adr(fw,k),0x01000001);
8092     // call to add_ptp_handler, try to follow
8093     if (adr == fadr)
8094     {
8095         find_ptp_handler_imm(fw,k);
8096     }
8097 
8098     return 0;
8099 }
8100 
8101 void find_ptp_handlers(firmware *fw)
8102 {
8103     int k = get_saved_sig(fw,"add_ptp_handler");
8104     if (k >= 0)
8105     {
8106         search_fw(fw, match_ptp_handlers, func_names[k].val, 0, 128);
8107     }
8108 }
8109 
8110 void write_levent_table_dump(firmware *fw, uint32_t tadr)
8111 {
8112     char *str;
8113     uint32_t lid = 0;
8114     uint32_t val;
8115     if (!tadr) {
8116         return;
8117     }
8118     FILE *f=fopen("levent_table.txt","w");
8119     if(!f) {
8120         return;
8121     }
8122     fprintf(f,"address    ID     (unknown)  name\n");
8123 
8124     for(;;tadr += 12) {
8125         val = *(uint32_t*)adr2ptr(fw, tadr);
8126         if ((val == 0xffffffff) || (val == 0) || (*(uint32_t*)adr2ptr(fw, tadr+4) < lid)) {
8127             break;
8128         }
8129         lid = *(uint32_t*)adr2ptr(fw, tadr+4);
8130         str = (char*)adr2ptr(fw,val);
8131         if (str) {
8132             fprintf(f,"0x%08x 0x%04x 0x%08x %s\n",tadr,lid,*(uint32_t*)adr2ptr(fw, tadr+8),str);
8133         }
8134     }
8135     fclose(f);
8136 }
8137 
8138 //------------------------------------------------------------------------------------------------------------
8139 
8140 // Write out firmware info
8141 void output_firmware_vals(firmware *fw)
8142 {
8143     bprintf("// Camera info:\n");
8144 
8145     if (fw->dryos_ver == 0)
8146     {
8147         bprintf("//   Can't find DRYOS version !!!\n\n");
8148     }
8149     else
8150     {
8151         if (fw->dryos_ver < fw->real_dryos_ver) // check for outdated finsig
8152             bprintf("//   DRYOS R%d (%s) *** New DRYOS Version - please update finsig_dryos.c ***\n",fw->real_dryos_ver,fw->dryos_ver_str);
8153         else
8154             bprintf("//   DRYOS R%d (%s)\n",fw->dryos_ver,fw->dryos_ver_str);
8155     }
8156 
8157     if (fw->firmware_ver_str == 0)
8158     {
8159         bprintf("//   Can't find firmware version !!!\n\n");
8160     }
8161     else
8162     {
8163         uint32_t j = idx2adr(fw,fw->fwver_idx);
8164         char *c = strrchr(fw->firmware_ver_str,' ') + 1; // points after the last space char
8165         uint32_t k = j + c - fw->firmware_ver_str;
8166         if ( (k>=j) && (k<j+32) )
8167         {
8168             bprintf("//   %s   // Found @ 0x%08x, \"%s\" @ 0x%08x\n",fw->firmware_ver_str,j,c,k);
8169         }
8170         else
8171         {
8172             // no space found in string (shouldn't happen)
8173             bprintf("//   %s   // Found @ 0x%08x, \"%s\" @ 0x%08x\n",fw->firmware_ver_str,j,fw->firmware_ver_str,j);
8174         }
8175     }
8176 
8177     if (fw->fw_build_date != 0)
8178     {
8179         bprintf("//   Firmware build timestamp: %s %s\n",fw->fw_build_date, (fw->fw_build_time==0)?"":fw->fw_build_time);
8180     }
8181 
8182     if (fw->fsize > (fw->size + 256))
8183     {
8184         bprintf("//   Possible corrupt firmware dump - file size too small for start address 0x%08x\n",fw->base);
8185         bprintf("//     file size = %.2fMB, should be %.2fMB\n", ((double)fw->size*4.0)/(1024.0*1024.0),((double)fw->fsize*4.0)/(1024.0*1024.0));
8186     }
8187 
8188     if (fw->cam != 0)
8189     {
8190         bprintf("//   %s\n",fw->cam);
8191     }
8192     else
8193     {
8194         bprintf("//   Could not find Camera name - possible corrupt firmware dump\n");
8195     }
8196 
8197     bprintf("\n// Values for makefile.inc\n");
8198 
8199     // work out digic version
8200     int digicver = 0;
8201     char *digics = "";
8202     if (fw->uncached_adr == 0x10000000)
8203     {
8204         digicver = 20;
8205         digics = "DIGIC II";
8206         if (find_str(fw,"FaceFrame") != -1) // face recognition related task
8207         {
8208             digics = "DIGIC III";
8209             digicver = 30;
8210         }
8211     }
8212     else
8213     {
8214         digicver = 40;
8215         digics = "DIGIC 4";
8216         if (find_str(fw,"\xac\xd0\x22\xc0") != -1) // 0xc022d0ac, D4+ GPIO
8217         {
8218             digicver = 41;
8219             digics = "DIGIC 4+";
8220         }
8221         else if (find_str(fw,"\xac\xc0\x22\xc0") != -1) // 0xc022c0ac, D5 GPIO
8222         {
8223             digicver = 50;
8224             digics = "DIGIC 5";
8225         }
8226     }
8227     bprintf("//   DIGIC = %i# %s\n",digicver,digics);
8228 
8229     bprintf("//   PLATFORMOSVER = %d\n",fw->real_dryos_ver);
8230 
8231     if (fw->pid != 0)
8232     {
8233         bprintf("//   PLATFORMID = %d# (0x%04x) Found @ 0x%08x\n",fw->pid,fw->pid,fw->pid_adr);
8234     }
8235     else
8236     {
8237         bprintf("//   PLATFORMID = ?           // Not found @ 0x%08x\n",fw->pid_adr);
8238     }
8239 
8240     if (fw->maxram != 0)
8241         bprintf("//   MAXRAMADDR = 0x%08x\n",fw->maxram);
8242 
8243     if (fw->memisostart != 0)
8244     {
8245         osig *o = find_match(fw->sv->makevals, "MEMISOSTART", fw->memisostart);
8246         if (o && (o->val == fw->memisostart))
8247             bprintf("//   MEMISOSTART = 0x%08x\n",fw->memisostart);
8248         else
8249             bprintf("//   MEMISOSTART = 0x%08x  (*** DOES NOT MATCH MAKEFILE VALUE 0x%08x***)\n",fw->memisostart,(o)?o->val:0);
8250     }
8251 
8252     if (fw->ksys != 0)
8253     {
8254         bprintf("//   KEYSYS = %s# Found @ 0x%08x\n",fw->ksys,idx2adr(fw,fw->ksys_idx));
8255 
8256         if (fw->dancing_bits_idx != 0)
8257         {
8258             if (fw->dancing_bits)
8259             {
8260                 bprintf("//   NEED_ENCODED_DISKBOOT = %d# Found @ 0x%08x",fw->dancing_bits,idx2adr(fw,fw->dancing_bits_idx));
8261                 osig *o = find_sig(fw->sv->makevals,"NEED_ENCODED_DISKBOOT");
8262                 if (o == 0)
8263                     bprintf(" (*** NOT IN MAKEFILE.INC ***)");
8264                 else if (o->val != fw->dancing_bits)
8265                     bprintf(" (*** DOES NOT MATCH MAKEFILE.INC VALUE %d ***)",o->val);
8266                 bprintf("\n");
8267             }
8268             else
8269             {
8270                 bprintf("//   NEED_ENCODED_DISKBOOT = ? Not found, possible new 'dancing bits' entry needed. // Found @ 0x%08x\n",idx2adr(fw,fw->dancing_bits_idx));
8271             }
8272         }
8273     }
8274 
8275     find_AdditionAgent_RAM(fw);
8276 
8277     bprintf("\n");
8278 
8279     uint32_t u = fw->base+fw->fsize*4;
8280     // make it fit in 32bits
8281     if (u == 0)
8282         u = 0xffffffff;
8283     bprintf("// Detected address ranges:\n");
8284     bprintf("// %-8s 0x%08x - 0x%08x (%7d bytes)\n","ROM",fw->base,u,fw->fsize*4);
8285     if ((fw->dryos_ver >= 50) && (fw->base2 != 0))
8286     {
8287         bprintf("// %-8s 0x%08x - 0x%08x copied from 0x%08x (%7d bytes)\n","RAM code",fw->base2,fw->base2+fw->size2*4,fw->base_copied,fw->size2*4);
8288     }
8289     bprintf("// %-8s 0x%08x - 0x%08x copied from 0x%08x (%7d bytes)\n","RAM data",fw->data_start,fw->data_start+fw->data_len*4,fw->data_init_start,fw->data_len*4);
8290 
8291     bprintf("\n");
8292 }
8293 
8294 int compare_func_names(const func_entry **p1, const func_entry **p2)
8295 {
8296     int rv = strcasecmp((*p1)->name, (*p2)->name);     // Case insensitive
8297     if (rv != 0)
8298         return rv;
8299     rv = strcmp((*p1)->name, (*p2)->name);          // Case sensitive (if equal with insensitive test)
8300     if (rv != 0)
8301         return rv;
8302     if ((*p1)->val < (*p2)->val)
8303         return -1;
8304     else if ((*p1)->val > (*p2)->val)
8305         return 1;
8306     return 0;
8307 }
8308 
8309 int compare_func_addresses(const func_entry **p1, const func_entry **p2)
8310 {
8311     if ((*p1)->val < (*p2)->val)
8312         return -1;
8313     else if ((*p1)->val > (*p2)->val)
8314         return 1;
8315     return compare_func_names(p1,p2);
8316 }
8317 
8318 void write_funcs(firmware *fw, char *filename, func_entry *fns[], int (*compare)(const func_entry **p1, const func_entry **p2))
8319 {
8320     int k;
8321 
8322     qsort(fns, next_func_entry, sizeof(func_entry*), (void*)compare);
8323 
8324     FILE *out_fp = fopen(filename, "w");
8325     for (k=0; k<next_func_entry; k++)
8326     {
8327         if (strncmp(fns[k]->name,"hook_",5) != 0)
8328         {
8329             if (fns[k]->val != 0)
8330             {
8331                 if (fns[k]->flags & BAD_MATCH)
8332                 {
8333                     osig* ostub2 = find_sig(fw->sv->stubs,fns[k]->name);
8334                     if (ostub2 && ostub2->val)
8335                         fprintf(out_fp, "0x%08x,%s,(stubs_entry_2.s)\n", ostub2->val, fns[k]->name);
8336                 }
8337                 else
8338                     fprintf(out_fp, "0x%08x,%s\n", fns[k]->val, fns[k]->name);
8339             }
8340 #ifdef LIST_IMPORTANT_FUNCTIONS
8341             else if (fns[k]->flags & LIST_ALWAYS)
8342             {
8343                 // helps development by listing important functions even when not found
8344                 fprintf(out_fp, "0,%s,(NOT FOUND)\n", fns[k]->name);
8345             }
8346 #endif
8347         }
8348     }
8349     fclose(out_fp);
8350 }
8351 
8352 int main(int argc, char **argv)
8353 {
8354     firmware fw;
8355     int k;
8356     int ret = 0;
8357     const char *curr_name;
8358 
8359     clock_t t1 = clock();
8360 
8361     if ((argc < 4) || (argc > 5))
8362         usage("args");
8363 
8364     out_fp = fopen(argv[3],"w");
8365     if (out_fp == NULL) usage("failed to open outputfile");
8366 
8367     for (next_func_entry = 0; func_names[next_func_entry].name != 0; next_func_entry++);
8368     int max_find_func = next_func_entry;
8369 
8370     fw.sv = new_stub_values();
8371     load_stubs(fw.sv, "stubs_entry_2.S", 1);
8372     load_stubs_min(fw.sv);
8373     load_modemap(fw.sv);
8374     load_platform(fw.sv);
8375     load_makefile(fw.sv);
8376 
8377     bprintf("// !!! THIS FILE IS GENERATED. DO NOT EDIT. !!!\n");
8378     bprintf("#include \"stubs_asm.h\"\n\n");
8379 
8380     load_firmware(&fw,argv[1],argv[2],(argc==5)?argv[4]:0, OS_DRYOS);
8381     fw.uncached_adr = 0;
8382     fw.uncached_adr_idx = 0;
8383     find_eventprocs(&fw);
8384     find_ptp_handlers(&fw);
8385     find_builddate(&fw);
8386     if (!fw.uncached_adr)
8387         search_saved_sig(&fw, "FreeUncacheableMemory", match_CAM_UNCACHED_BIT, 0, 0, 8);
8388     output_firmware_vals(&fw);
8389 
8390     out_hdr = 1;
8391     bprintf("// Stubs below should be checked. Stub not matched 100%%, or difference found to current 'stubs_entry_2.S'\n");
8392     bprintf("//    Name                                     Address      Rule  %%  Comp to stubs_entry_2.S\n");
8393     out_hdr = 0;
8394     bprintf("// Stubs below matched 100%%.\n");
8395     bprintf("//    Name                                     Address                Comp to stubs_entry_2.S\n");
8396 
8397     find_tasks(&fw);
8398     if(get_saved_sig(&fw,"task_ComWireless") >= 0) {
8399         cam_has_wifi = 1;
8400     }
8401 
8402     for (k = 0; k < max_find_func; k++)
8403     {
8404         count = 0;
8405         curr_name = func_names[k].name;
8406 
8407         if ((fw.dryos_ver >= find_min_ver(curr_name)) && (fw.dryos_ver <= find_max_ver(curr_name)))
8408         {
8409             find_matches(&fw, curr_name);
8410             print_results(&fw,curr_name,k);
8411 
8412             if (count == 0)
8413             {
8414                 ret = 1;
8415             }
8416         }
8417     }
8418 
8419     find_modemap(&fw);
8420     find_stubs_min(&fw);
8421     find_lib_vals(&fw);
8422     find_key_vals(&fw);
8423     find_platform_vals(&fw);
8424     find_propset(&fw);
8425     find_other_vals(&fw);
8426 
8427     write_output();
8428 
8429     fclose(out_fp);
8430 
8431     func_entry *fns[MAX_FUNC_ENTRY];
8432     for (k=0; k<next_func_entry; k++)
8433         fns[k] = &func_names[k];
8434 
8435     write_funcs(&fw, "funcs_by_name.csv", fns, compare_func_names);
8436     write_funcs(&fw, "funcs_by_address.csv", fns, compare_func_addresses);
8437 
8438     clock_t t2 = clock();
8439 
8440     printf("Time to generate stubs %.2f seconds\n",(double)(t2-t1)/(double)CLOCKS_PER_SEC);
8441 
8442     return ret;
8443 }
8444 
8445 //------------------------------------------------------------------------------------------------------------

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