root/tools/finsig_dryos.c

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

DEFINITIONS

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

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

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