-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Start mixed-language library overhaul
- Loading branch information
Showing
9 changed files
with
382 additions
and
29 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
--- @module context | ||
|
||
local uc_c = require("unicorn_c_") | ||
|
||
local ContextMethods = {} | ||
local ContextMeta = {__index = ContextMethods} | ||
|
||
function Context(engine, context_handle) | ||
if context_handle == nil then | ||
context_handle = uc_c.context_save(engine) | ||
end | ||
|
||
-- We want to hold a weak reference to the engine so that this context laying around | ||
-- won't prevent it from being collected, but we do need to hold a strong reference to | ||
-- the handle returned to us by Unicorn. Thus, we need to put the engine into a weak | ||
-- table instead of directly in the Context object. | ||
local instance = { | ||
engine_ref_ = setmetatable({engine = engine}, {__mode = "v"}), | ||
handle_ = context_handle, | ||
} | ||
|
||
return setmetatable(instance, ContextMeta) | ||
end | ||
|
||
|
||
function ContextMeta:__close() | ||
if self.handle_ ~= nil then | ||
self:free() | ||
end | ||
end | ||
|
||
|
||
function ContextMeta:__gc() | ||
if self.handle_ ~= nil then | ||
self:free() | ||
end | ||
end | ||
|
||
|
||
function ContextMethods:free() | ||
if self.handle_ == nil then | ||
error("Attempted to free the same context twice.") | ||
end | ||
|
||
-- The engine reference can be nil in two cases: 1) the engine was collected, or 2) | ||
-- this is a double free. We need to check for a double free first, as that's a user | ||
-- bug. This is more serious. | ||
if self.engine_ref_.engine == nil then | ||
error("BUG: Engine was garbage collected before a context.") | ||
end | ||
|
||
uc_c.context_free(self.engine_ref_.engine, self.handle_) | ||
self.engine_ref_.engine = nil | ||
self.handle_ = nil | ||
end | ||
|
||
|
||
return {Context = Context} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,229 @@ | ||
--- @module engine | ||
|
||
local uc_c = require("unicorn_c_") | ||
local uc_context = require("unicorn.context") | ||
|
||
local EngineMethods = {} | ||
local EngineMeta = {__index = EngineMethods} | ||
|
||
|
||
--- Create an object-oriented wrapper around an opened Unicorn engine. | ||
--- | ||
--- @param handle A handle returned by the Unicorn C library (not the lua binding). | ||
function Engine(handle) | ||
local instance = { | ||
engine_handle_ = handle, | ||
-- Once a context object is unreachable, it can't be used to restore the engine to | ||
-- the state the context describes. Since there's no point to holding onto a | ||
-- context the user can no longer use, we use a weak table to store them to allow | ||
-- them to be garbage collected once the user can't use them anymore. | ||
-- | ||
-- We still need this table because if there are active contexts laying around | ||
-- when the engine is closed, we need to release those as well. | ||
contexts_ = setmetatable({}, {__mode = "k"}), | ||
hooks_ = {}, | ||
} | ||
|
||
return setmetatable(instance, EngineMeta) | ||
end | ||
|
||
function EngineMeta:__close() | ||
-- Only close the engine if it hasn't been closed already. We want to allow double- | ||
-- closing here because the user may want to explicitly close an engine on some | ||
-- control paths, but let Lua automatically close it on others. | ||
if self.engine_handle_ ~= nil then | ||
self:close() | ||
end | ||
end | ||
|
||
function EngineMeta:__gc() | ||
if self.engine_handle_ ~= nil then | ||
self:close() | ||
end | ||
end | ||
|
||
--- Stop the emulator engine and free all resources. | ||
--- | ||
--- This removes all hooks, frees contexts and memory, then closes the underlying Unicorn | ||
--- engine. The object must not be used after this is called. | ||
function EngineMethods:close() | ||
if self.engine_handle_ == nil then | ||
error("Attempted to close an engine twice.") | ||
end | ||
|
||
self:emu_stop() | ||
uc_c.close(self.engine_handle_) | ||
|
||
-- We need to delete the handle so that when the garbage collector runs, we don't try | ||
-- closing an already deallocated engine. | ||
self.engine_handle_ = nil | ||
end | ||
|
||
function EngineMethods:context_restore(context) | ||
return uc_c.context_restore(self.engine_handle_, context.context_handle_) | ||
end | ||
|
||
function EngineMethods:context_save(context) | ||
local context_handle = uc_c.context_save(self.engine_handle_, context) | ||
return uc_context.Context(self.engine_handle_, context_handle) | ||
end | ||
|
||
function EngineMethods:emu_start(start_addr, end_addr, timeout, n_instructions) | ||
return uc_c.emu_start( | ||
self.engine_handle_, | ||
start_addr, | ||
end_addr, | ||
timeout or 0, | ||
n_instructions or 0 | ||
) | ||
end | ||
|
||
function EngineMethods:emu_stop() | ||
for context in pairs(self.contexts_) do | ||
context:free() | ||
end | ||
self.contexts_ = {} | ||
|
||
for hook_handle in pairs(self.hooks_) do | ||
hook_handle:close() | ||
end | ||
self.hooks_ = {} | ||
|
||
uc_c.emu_stop(self.engine_handle_) | ||
end | ||
|
||
function EngineMethods:errno() | ||
return uc_c.errno(self.engine_handle_) | ||
end | ||
|
||
function EngineMethods:hook_add() | ||
error("Not implemented yet") | ||
end | ||
|
||
function EngineMethods:hook_del() | ||
error("Not implemented yet") | ||
end | ||
|
||
function EngineMethods:mem_map() | ||
error("Not implemented yet") | ||
end | ||
|
||
function EngineMethods:mem_protect() | ||
error("Not implemented yet") | ||
end | ||
|
||
function EngineMethods:mem_read() | ||
error("Not implemented yet") | ||
end | ||
|
||
function EngineMethods:mem_regions() | ||
error("Not implemented yet") | ||
end | ||
|
||
function EngineMethods:mem_unmap() | ||
error("Not implemented yet") | ||
end | ||
|
||
function EngineMethods:mem_write() | ||
error("Not implemented yet") | ||
end | ||
|
||
function EngineMethods:query(query_flag) | ||
return uc_c.query(self.engine_handle_, query_flag) | ||
end | ||
|
||
function EngineMethods:reg_read() | ||
error("Not implemented yet") | ||
end | ||
|
||
function EngineMethods:reg_read_as() | ||
error("Not implemented yet") | ||
end | ||
|
||
function EngineMethods:reg_read_batch() | ||
error("Not implemented yet") | ||
end | ||
|
||
function EngineMethods:reg_read_batch_as() | ||
error("Not implemented yet") | ||
end | ||
|
||
function EngineMethods:reg_write() | ||
error("Not implemented yet") | ||
end | ||
|
||
function EngineMethods:reg_write_as() | ||
error("Not implemented yet") | ||
end | ||
|
||
function EngineMethods:reg_write_batch() | ||
error("Not implemented yet") | ||
end | ||
|
||
|
||
-- These functions are only available in Unicorn 2.x. | ||
if uc_c.version()[1] > 1 then | ||
function EngineMethods:ctl_exits_disable() | ||
return uc_c.ctl_exits_disable(self.engine_handle_) | ||
end | ||
|
||
function EngineMethods:ctl_exits_enable() | ||
return uc_c.ctl_exits_enable(self.engine_handle_) | ||
end | ||
|
||
function EngineMethods:ctl_flush_tlb() | ||
return uc_c.ctl_flush_tlb(self.engine_handle_) | ||
end | ||
|
||
function EngineMethods:ctl_get_arch() | ||
return uc_c.ctl_get_arch(self.engine_handle_) | ||
end | ||
|
||
function EngineMethods:ctl_get_cpu_model() | ||
return uc_c.ctl_get_cpu_model(self.engine_handle_) | ||
end | ||
|
||
function EngineMethods:ctl_get_exits() | ||
error("Not implemented yet") | ||
end | ||
|
||
function EngineMethods:ctl_get_exits_cnt() | ||
return uc_c.ctl_get_exits_cnt(self.engine_handle_) | ||
end | ||
|
||
function EngineMethods:ctl_get_mode() | ||
return uc_c.ctl_get_mode(self.engine_handle_) | ||
end | ||
|
||
function EngineMethods:ctl_get_page_size() | ||
error("Not implemented yet") | ||
end | ||
|
||
function EngineMethods:ctl_get_timeout() | ||
return uc_c.ctl_get_timeout(self.engine_handle_) | ||
end | ||
|
||
function EngineMethods:ctl_remove_cache() | ||
error("Not implemented yet") | ||
end | ||
|
||
function EngineMethods:ctl_request_cache() | ||
error("Not implemented yet") | ||
end | ||
|
||
function EngineMethods:ctl_set_cpu_model() | ||
error("Not implemented yet") | ||
end | ||
|
||
function EngineMethods:ctl_set_exits() | ||
error("Not implemented yet") | ||
end | ||
|
||
function EngineMethods:ctl_set_page_size() | ||
error("Not implemented yet") | ||
end | ||
end | ||
|
||
|
||
--- @export | ||
return {Engine = Engine} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
--- @module hooks |
Oops, something went wrong.