Executing Event Procedures by name - General Discussion and Assistance - CHDK Forum

Executing Event Procedures by name

  • 43 Replies
  • 25844 Views
*

Offline reyalp

  • ******
  • 14082
Executing Event Procedures by name
« on: 25 / October / 2009, 22:11:43 »
Advertisements
While working on the logicalevent functions, I realized that almost all the functions we want to uses are registered event procedures. There must be some way to call an event procedure by it's name, rather than finding all the functions addresses and adding them to stubs etc. This is something I've been meaning to look into for a long time, but this finally gave me the motivation to do it.

It turns out to be quite simple. ExecuteEventProcedure appears to take the name of the eventproc, followed by a vararg list of the arguments for the eventproc. If you try to call an unregistered eventproc, it helpfully returns -1. The eventprocs themselves appear to use normal C calling convention.

With some quick hacking, the following lua script plays the startup sound
Code: [Select]
r=exec_event_proc("RegisterProductTestEvent")
print(r)
sleep(1000)
r=exec_event_proc("PT_PlaySound",0x2001)
print(r)
sleep(1000)
(PT_ stands for product test, so the PT_ eventprocs aren't registered by default, but "RegisterProductTestEvent" is and this registers the others )

It will take a bit more hacking to make arbitrary event procs useful for lua, but this opens up huge possibilities. A large number of our stubs are already registered eventprocs.

Calling from C should be even easier, just ExecuteEventprocedure("foo",...). There will be a slight performance penalty for calling things this way, but for many functions it's probably worth it for the ease of maintenance.

There are more interesting possibilities too. We may be able to register our own replacements for some existing eventprocs (although you'd have to be careful, because some are called both directly from C and the eventproc interface), and modify some behavior without hooking whole tasks.
« Last Edit: 25 / October / 2009, 22:22:02 by reyalp »
Don't forget what the H stands for.

*

Offline RaduP

  • *****
  • 926
Re: Executing Event Procedures by name
« Reply #1 on: 25 / October / 2009, 22:23:04 »
Nice find!
Hijacking functions would be one of the coolest things ever, so long as they are called from the eventproc and not directly..
Did you check how this mechanism works? How does ExecuteEventProcedure associate the name of the function with the pointer? Is there some table or structure where this stuff is held? If so, it would be trivial to get all the functions in the stubs without messy and inaccurate signatures..

*

Offline reyalp

  • ******
  • 14082
Re: Executing Event Procedures by name
« Reply #2 on: 25 / October / 2009, 22:29:34 »
Nice find!
Hijacking functions would be one of the coolest things ever, so long as they are called from the eventproc and not directly..
Did you check how this mechanism works? How does ExecuteEventProcedure associate the name of the function with the pointer? Is there some table or structure where this stuff is held? If so, it would be trivial to get all the functions in the stubs without messy and inaccurate signatures..
I haven't dug into the details of look up, but I doubt it is too complicated.

You can look through ExecuteEventProcedure (which looks up functions names to execute them) ExportToEventProcedure which is one of several functions that registers them, and I just saw GetEventProcedureList ;)

eta:
Note that you can also just make a wrapper which calls the function by name with ExecuteEventProcedure
Don't forget what the H stands for.

*

Offline reyalp

  • ******
  • 14082
Re: Executing Event Procedures by name
« Reply #3 on: 25 / October / 2009, 22:41:52 »
Don't forget what the H stands for.


*

Offline reyalp

  • ******
  • 14082
Re: Executing Event Procedures by name
« Reply #4 on: 25 / October / 2009, 23:24:11 »
One difficulty: ExecuteEventProcedure appears to be a vararg function. As far as I know, there isn't any va_list equivalent. Yet to call it from thumb code, we need wrapper. You can't normally pass varargs on from one function to the next. Worse, tocall from lua, we need to build the varargs dynamically. All this needs to not break arm/thumb interworking.

I got around this in my test, knowing that arm vararg functions still pass the first 4 arguments in registers, so calling ExecuteEventProcedure with 4 fixed arguments should be compatible with the vararg version... the additional ones will just be ignored.

So guess we need some assembler to glue it together. For the wrapper it seems like we should be able to just do something like
Code: [Select]
int __attribute__((naked,noinline)) ExecuteEventProcedure(const char *name,...) {
asm(
"BL _ExecuteEventProcedure\n"
"BX LR\n"
);
}
But will this break interworking ?

edit:
of course the above needs to save LR, without messing with the stack
« Last Edit: 26 / October / 2009, 01:48:57 by reyalp »
Don't forget what the H stands for.

*

Offline RaduP

  • *****
  • 926
Re: Executing Event Procedures by name
« Reply #5 on: 25 / October / 2009, 23:34:29 »
Would it work to have a C function (thumb mode) that puts all the arguments in a list in the memory, then have a non thumb function that takes those arguments from the memory and place them in the registers/stack and then call ExecuteEventProcedure?

*

Offline reyalp

  • ******
  • 14082
Re: Executing Event Procedures by name
« Reply #6 on: 25 / October / 2009, 23:40:34 »
Would it work to have a C function (thumb mode) that puts all the arguments in a list in the memory, then have a non thumb function that takes those arguments from the memory and place them in the registers/stack and then call ExecuteEventProcedure?
Yes, but you need assembler to take those arguments and make them into a proper vararg call. If you are going to do that, you may as well not bother packing it up into a structure. Lua will have to do something like what you describe, since it doesn't know the number of arguments at compile time.

It looks like a BX LR return should be fine.

edit:
but without making a parallel stack just for the LR, there doesn't seem to be any way to do that.
« Last Edit: 26 / October / 2009, 01:59:07 by reyalp »
Don't forget what the H stands for.

*

Offline reyalp

  • ******
  • 14082
Re: Executing Event Procedures by name
« Reply #7 on: 26 / October / 2009, 22:15:19 »
Update:
Here's a patch that adds preliminary support for calling eventprocs from CHDK and lua code, along with a lua script that shows a few of them. ExecuteEventProcedure is already in the sig finder. I haven't verified that it gets it right on every camera, but it was correct on mine.

The sample script:
Mode... lets you select from the modes in the a540 modemap, and set them with SetCurrentCaptureModeType
ScriptMode is as described in the logical event thread, set using the SetScriptMode eventproc
The UIFS_ functions are some other functions in the same group as these. They mostly do what you'd expect from the name. Some observations
- UIFS_Capture takes a picture, but it takes two arguments who's meaning I don't know. 0,0 seems to work. Use at your own risk!
- UIFS_SetCaptureModeToMacro crashes my camera.
- UIFS_SetDialMovieRec will switch to from play to record mode, but won't switch to movie mode unless invoked a second time.
Buttons lets you try using some of the Press/Unpress events as eventprocs.

New lua function:
ret = exec_event_proc(name,...)
name is string containing the (case sensitive I assume) name of the event proc to execute.
The remaining parameters must be lua strings or numbers, and are passed to ExecuteEventProcedure in the vararg calling convention. Any strings passed must not be modified by the eventproc. If the eventproc treats a string as read/write, Bad Things will most likely happen.
ret is whatever was returned by ExecuteEventProc. This appears to be -1 if the named eventproc didn't exist.

The interface will change in the future!

Many eventprocs are only available if you first call another eventproc to register them. UI_RegistDebugEventProc registers most of those used above, including registering the logical events as eventprocs. The PT_ functions are available if you call "RegisterProductTestEvent"

Warning:
There are eventprocs that could destroy your camera ("EraseSectorOfRom" is an obvious example... the one that destroys your camera may not be obvious!)

Calling functions with incorrect parameters can also have bad results: When I called UIFS_Capture with random garbage in it's two expected arguments, the shutter mechanism on my camera basically freaked out, clicking rapidly until I held the power button down for a while.

If you are going to call a function, look at the dump to make sure you understand how many parameters it expects. If a function loads something into r0-r3 without using or saving the values in them first, then you know the function has at most that many parameters.

side note:
The function that allows us to call ExecuteEventProcedure can be utilized to allow lua to call any C function.

edit:
I have verified that ExecuteEventProcedure is found (though not necessarily correct) for every camera. I can provide builds if anyone is interested.
« Last Edit: 27 / October / 2009, 03:01:41 by reyalp »
Don't forget what the H stands for.


*

Offline RaduP

  • *****
  • 926
Re: Executing Event Procedures by name
« Reply #8 on: 27 / October / 2009, 19:04:40 »
Were you able to determine at what point those procedures are registered with ExecuteEventProcedure?
I was thinking, for example, that if they are initialized very early in the startup function, before the extended lens check, one could unregister the function that does the check, and register a null function instead.

*

Offline reyalp

  • ******
  • 14082
Re: Executing Event Procedures by name
« Reply #9 on: 27 / October / 2009, 19:32:36 »
Were you able to determine at what point those procedures are registered with ExecuteEventProcedure?
I was thinking, for example, that if they are initialized very early in the startup function, before the extended lens check, one could unregister the function that does the check, and register a null function instead.
Different functions are registered at different points. Most of the ones I've been using aren't registered at all by default, because they are canon debug/development functions. You have to call another eventproc to to register them.

Many functions are not called through the eventproc interface. I would expect this to include most error handlers. It's not actually clear to me why "normal" canon code uses eventprocs at all, although it seems to.
Don't forget what the H stands for.

 

Related Topics