From fdb350a4c98f070c264b8bd4ea9eca2513352f21 Mon Sep 17 00:00:00 2001 From: Richard Carlsson Date: Wed, 14 May 2014 14:46:46 +0200 Subject: Add 'md5' entry for module_info/0/1 functions. --- erts/emulator/beam/atom.names | 1 + erts/emulator/beam/beam_load.c | 56 ++++++++++++++++++++++++++++---- erts/emulator/beam/beam_load.h | 8 +++-- erts/emulator/test/module_info_SUITE.erl | 21 ++++++++++-- erts/preloaded/src/erlang.erl | 2 +- system/doc/reference_manual/modules.xml | 7 +++- 6 files changed, 81 insertions(+), 14 deletions(-) diff --git a/erts/emulator/beam/atom.names b/erts/emulator/beam/atom.names index d28e519ae1..7d11f7f956 100644 --- a/erts/emulator/beam/atom.names +++ b/erts/emulator/beam/atom.names @@ -333,6 +333,7 @@ atom max atom maximum atom max_tables max_processes atom mbuf_size +atom md5 atom memory atom memory_internal atom memory_types diff --git a/erts/emulator/beam/beam_load.c b/erts/emulator/beam/beam_load.c index e96177cfd9..5c98d5c0b5 100644 --- a/erts/emulator/beam/beam_load.c +++ b/erts/emulator/beam/beam_load.c @@ -245,7 +245,7 @@ typedef struct { /* * This structure contains all information about the module being loaded. */ - +#define MD5_SIZE 16 typedef struct LoaderState { /* * The current logical file within the binary. @@ -292,7 +292,7 @@ typedef struct LoaderState { StringPatch* string_patches; /* Linked list of position into string table to patch. */ BeamInstr catches; /* Linked list of catch_yf instructions. */ unsigned loaded_size; /* Final size of code when loaded. */ - byte mod_md5[16]; /* MD5 for module code. */ + byte mod_md5[MD5_SIZE]; /* MD5 for module code. */ int may_load_nif; /* true if NIFs may later be loaded for this module */ int on_load; /* Index in the code for the on_load function * (or 0 if there is no on_load function) @@ -528,6 +528,7 @@ static Eterm exported_from_module(Process* p, Eterm mod); static Eterm functions_in_module(Process* p, Eterm mod); static Eterm attributes_for_module(Process* p, Eterm mod); static Eterm compilation_info_for_module(Process* p, Eterm mod); +static Eterm md5_of_module(Process* p, Eterm mod); static Eterm native_addresses(Process* p, Eterm mod); int patch_funentries(Eterm Patchlist); int patch(Eterm Addresses, Uint fe); @@ -648,6 +649,7 @@ erts_prepare_loading(Binary* magic, Process *c_p, Eterm group_leader, stp->code[MI_COMPILE_PTR] = 0; stp->code[MI_COMPILE_SIZE] = 0; stp->code[MI_COMPILE_SIZE_ON_HEAP] = 0; + stp->code[MI_MD5_PTR] = 0; /* * Read the atom table. @@ -4038,7 +4040,7 @@ freeze_code(LoaderState* stp) } size = (stp->ci * sizeof(BeamInstr)) + (stp->total_literal_size * sizeof(Eterm)) + - strtab_size + attr_size + compile_size + line_size; + strtab_size + attr_size + compile_size + MD5_SIZE + line_size; /* * Move the code to its final location. @@ -4247,11 +4249,20 @@ freeze_code(LoaderState* stp) code[MI_COMPILE_SIZE_ON_HEAP] = decoded_size; } CHKBLK(ERTS_ALC_T_CODE,code); + { + byte* md5_sum = str_table + strtab_size + attr_size + compile_size; + CHKBLK(ERTS_ALC_T_CODE,code); + sys_memcpy(md5_sum, stp->mod_md5, MD5_SIZE); + CHKBLK(ERTS_ALC_T_CODE,code); + code[MI_MD5_PTR] = (BeamInstr) md5_sum; + CHKBLK(ERTS_ALC_T_CODE,code); + } + CHKBLK(ERTS_ALC_T_CODE,code); /* * Make sure that we have not overflowed the allocated code space. */ - ASSERT(str_table + strtab_size + attr_size + compile_size == + ASSERT(str_table + strtab_size + attr_size + compile_size + MD5_SIZE == ((byte *) code) + size); /* @@ -5103,6 +5114,7 @@ erts_module_info_0(Process* p, Eterm module) hp += 3; \ list = CONS(hp, tup, list) + BUILD_INFO(am_md5); BUILD_INFO(am_compile); BUILD_INFO(am_attributes); BUILD_INFO(am_imports); @@ -5118,6 +5130,8 @@ erts_module_info_1(Process* p, Eterm module, Eterm what) return module; } else if (what == am_imports) { return NIL; + } else if (what == am_md5) { + return md5_of_module(p, module); } else if (what == am_exports) { return exported_from_module(p, module); } else if (what == am_functions) { @@ -5306,7 +5320,7 @@ attributes_for_module(Process* p, /* Process whose heap to use. */ Eterm result = NIL; Eterm* end; - if (is_not_atom(mod) || (is_not_list(result) && is_not_nil(result))) { + if (is_not_atom(mod)) { return THE_NON_VALUE; } @@ -5345,7 +5359,7 @@ compilation_info_for_module(Process* p, /* Process whose heap to use. */ Eterm result = NIL; Eterm* end; - if (is_not_atom(mod) || (is_not_list(result) && is_not_nil(result))) { + if (is_not_atom(mod)) { return THE_NON_VALUE; } @@ -5367,6 +5381,33 @@ compilation_info_for_module(Process* p, /* Process whose heap to use. */ return result; } +/* + * Returns the MD5 checksum for a module + * + * Returns a tagged term, or 0 on error. + */ + +Eterm +md5_of_module(Process* p, /* Process whose heap to use. */ + Eterm mod) /* Tagged atom for module. */ +{ + Module* modp; + BeamInstr* code; + Eterm res = NIL; + + if (is_not_atom(mod)) { + return THE_NON_VALUE; + } + + modp = erts_get_module(mod, erts_active_code_ix()); + if (modp == NULL) { + return THE_NON_VALUE; + } + code = modp->curr.code; + res = new_binary(p, (byte *) code[MI_MD5_PTR], MD5_SIZE); + return res; +} + /* * Build a single {M,F,A,Loction} item to be part of * a stack trace. @@ -5543,7 +5584,7 @@ code_module_md5_1(BIF_ALIST_1) res = am_undefined; goto done; } - res = new_binary(p, stp->mod_md5, sizeof(stp->mod_md5)); + res = new_binary(p, stp->mod_md5, MD5_SIZE); done: erts_free_aligned_binary_bytes(temp_alloc); @@ -5939,6 +5980,7 @@ erts_make_stub_module(Process* p, Eterm Mod, Eterm Beam, Eterm Info) code[MI_LITERALS_END] = 0; code[MI_LITERALS_OFF_HEAP] = 0; code[MI_ON_LOAD_FUNCTION_PTR] = 0; + code[MI_MD5_PTR] = 0; ci = MI_FUNCTIONS + n + 1; /* diff --git a/erts/emulator/beam/beam_load.h b/erts/emulator/beam/beam_load.h index bd22b0c4de..0e3ca0bdb0 100644 --- a/erts/emulator/beam/beam_load.h +++ b/erts/emulator/beam/beam_load.h @@ -91,7 +91,6 @@ extern Uint erts_total_code_size; #define MI_LITERALS_END 8 #define MI_LITERALS_OFF_HEAP 9 - /* * Pointer to the on_load function (or NULL if none). */ @@ -102,6 +101,11 @@ extern Uint erts_total_code_size; */ #define MI_LINE_TABLE 11 +/* + * Pointer to the module MD5 sum (16 bytes) + */ +#define MI_MD5_PTR 12 + /* * Start of function pointer table. This table contains pointers to * all functions in the module plus an additional pointer just beyond @@ -111,7 +115,7 @@ extern Uint erts_total_code_size; * this table. */ -#define MI_FUNCTIONS 12 +#define MI_FUNCTIONS 13 /* * Layout of the line table. diff --git a/erts/emulator/test/module_info_SUITE.erl b/erts/emulator/test/module_info_SUITE.erl index 8a63d9fe3e..06cd2a9b9a 100644 --- a/erts/emulator/test/module_info_SUITE.erl +++ b/erts/emulator/test/module_info_SUITE.erl @@ -24,7 +24,7 @@ -export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, init_per_group/2,end_per_group/2, init_per_testcase/2,end_per_testcase/2, - exports/1,functions/1,native/1]). + exports/1,functions/1,native/1,info/1]). %%-compile(native). @@ -52,8 +52,8 @@ end_per_group(_GroupName, Config) -> Config. -modules() -> - [exports, functions, native]. +modules() -> + [exports, functions, native, info]. init_per_testcase(Func, Config) when is_atom(Func), is_list(Config) -> Dog = ?t:timetrap(?t:minutes(3)), @@ -122,6 +122,21 @@ native_proj({Name,Arity,Addr}) -> native_filter(Set) -> sofs:no_elements(Set) =/= 1. +%% Test that the module info of this module is correct. Use +%% erlang:get_module_info(?MODULE) to avoid compiler optimization tricks. +info(Config) when is_list(Config) -> + Info = erlang:get_module_info(?MODULE), + All = all_exported(), + {ok,{?MODULE,MD5}} = beam_lib:md5(code:which(?MODULE)), + {md5, MD5} = lists:keyfind(md5, 1, Info), + {exports, Exports} = lists:keyfind(exports, 1, Info), + All = lists:sort(Exports), + {attributes, Attrs} = lists:keyfind(attributes, 1, Info), + {vsn,_} = lists:keyfind(vsn, 1, Attrs), + {compile, Compile} = lists:keyfind(compile, 1, Info), + {options,_} = lists:keyfind(options, 1, Compile), + ok. + %% Helper functions (local). add_arity(L) -> diff --git a/erts/preloaded/src/erlang.erl b/erts/preloaded/src/erlang.erl index cabbbd191f..bcc1250abd 100644 --- a/erts/preloaded/src/erlang.erl +++ b/erts/preloaded/src/erlang.erl @@ -1664,7 +1664,7 @@ element(_N, _Tuple) -> %% Not documented -spec erlang:get_module_info(Module, Item) -> ModuleInfo when Module :: atom(), - Item :: module | imports | exports | functions | attributes | compile | native_addresses, + Item :: module | imports | exports | functions | attributes | compile | native_addresses | md5, ModuleInfo :: atom() | [] | [{atom(), arity()}] | [{atom(), term()}] | [{atom(), arity(), integer()}]. get_module_info(_Module, _Item) -> erlang:nif_error(undefined). diff --git a/system/doc/reference_manual/modules.xml b/system/doc/reference_manual/modules.xml index f0ec7ef165..c8f443d9dd 100644 --- a/system/doc/reference_manual/modules.xml +++ b/system/doc/reference_manual/modules.xml @@ -230,7 +230,7 @@ behaviour_info(callbacks) -> Callbacks. a list of {Key,Value} tuples with information about the module. Currently, the list contain tuples with the following Keys: attributes, compile, - exports, and imports. The order and number of tuples + exports, imports and md5. The order and number of tuples may change without prior notice.

The {imports,Value} tuple may be removed in a future @@ -273,6 +273,11 @@ behaviour_info(callbacks) -> Callbacks. be supported in future release.

+ md5 + +

Return a binary representing the MD5 checksum of the module.

+
+ exports

Return a list of {Name,Arity} tuples with -- cgit v1.2.3 From 4ad572a8b66df8174d92157411326aab95ee8124 Mon Sep 17 00:00:00 2001 From: Richard Carlsson Date: Wed, 14 May 2014 14:49:10 +0200 Subject: Add 'module' entry for module_info/0 function for completeness as it exist in module_info/1. --- erts/emulator/beam/beam_load.c | 1 + erts/emulator/test/module_info_SUITE.erl | 1 + system/doc/reference_manual/modules.xml | 7 ++++++- 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/erts/emulator/beam/beam_load.c b/erts/emulator/beam/beam_load.c index 5c98d5c0b5..8b3fc90826 100644 --- a/erts/emulator/beam/beam_load.c +++ b/erts/emulator/beam/beam_load.c @@ -5119,6 +5119,7 @@ erts_module_info_0(Process* p, Eterm module) BUILD_INFO(am_attributes); BUILD_INFO(am_imports); BUILD_INFO(am_exports); + BUILD_INFO(am_module); #undef BUILD_INFO return list; } diff --git a/erts/emulator/test/module_info_SUITE.erl b/erts/emulator/test/module_info_SUITE.erl index 06cd2a9b9a..f3986f0c4f 100644 --- a/erts/emulator/test/module_info_SUITE.erl +++ b/erts/emulator/test/module_info_SUITE.erl @@ -128,6 +128,7 @@ info(Config) when is_list(Config) -> Info = erlang:get_module_info(?MODULE), All = all_exported(), {ok,{?MODULE,MD5}} = beam_lib:md5(code:which(?MODULE)), + {module, ?MODULE} = lists:keyfind(module, 1, Info), {md5, MD5} = lists:keyfind(md5, 1, Info), {exports, Exports} = lists:keyfind(exports, 1, Info), All = lists:sort(Exports), diff --git a/system/doc/reference_manual/modules.xml b/system/doc/reference_manual/modules.xml index c8f443d9dd..ac778805fe 100644 --- a/system/doc/reference_manual/modules.xml +++ b/system/doc/reference_manual/modules.xml @@ -229,7 +229,7 @@ behaviour_info(callbacks) -> Callbacks.

The module_info/0 function in each module returns a list of {Key,Value} tuples with information about the module. Currently, the list contain tuples with the following - Keys: attributes, compile, + Keys: module, attributes, compile, exports, imports and md5. The order and number of tuples may change without prior notice.

@@ -246,6 +246,11 @@ behaviour_info(callbacks) -> Callbacks.

The following values are allowed for Key:

+ module + +

Return an atom representing the module name.

+
+ attributes

Return a list of {AttributeName,ValueList} tuples, -- cgit v1.2.3 From 0dbcbea0cf52672ef1cf051c3cd7640eb7ff728e Mon Sep 17 00:00:00 2001 From: Richard Carlsson Date: Wed, 14 May 2014 14:54:16 +0200 Subject: Remove obsolete 'imports' entry from module_info/1/2 functions It previously always returned an empty list and was documented to be removed. --- erts/emulator/beam/atom.names | 1 - erts/emulator/beam/beam_load.c | 3 --- system/doc/reference_manual/modules.xml | 12 +----------- 3 files changed, 1 insertion(+), 15 deletions(-) diff --git a/erts/emulator/beam/atom.names b/erts/emulator/beam/atom.names index 7d11f7f956..dc930f2d38 100644 --- a/erts/emulator/beam/atom.names +++ b/erts/emulator/beam/atom.names @@ -278,7 +278,6 @@ atom http httph https http_response http_request http_header http_eoh http_error atom id atom if_clause atom ignore -atom imports atom in atom in_exiting atom inactive diff --git a/erts/emulator/beam/beam_load.c b/erts/emulator/beam/beam_load.c index 8b3fc90826..a4e72a130a 100644 --- a/erts/emulator/beam/beam_load.c +++ b/erts/emulator/beam/beam_load.c @@ -5117,7 +5117,6 @@ erts_module_info_0(Process* p, Eterm module) BUILD_INFO(am_md5); BUILD_INFO(am_compile); BUILD_INFO(am_attributes); - BUILD_INFO(am_imports); BUILD_INFO(am_exports); BUILD_INFO(am_module); #undef BUILD_INFO @@ -5129,8 +5128,6 @@ erts_module_info_1(Process* p, Eterm module, Eterm what) { if (what == am_module) { return module; - } else if (what == am_imports) { - return NIL; } else if (what == am_md5) { return md5_of_module(p, module); } else if (what == am_exports) { diff --git a/system/doc/reference_manual/modules.xml b/system/doc/reference_manual/modules.xml index ac778805fe..5fc8b363f8 100644 --- a/system/doc/reference_manual/modules.xml +++ b/system/doc/reference_manual/modules.xml @@ -230,12 +230,8 @@ behaviour_info(callbacks) -> Callbacks. a list of {Key,Value} tuples with information about the module. Currently, the list contain tuples with the following Keys: module, attributes, compile, - exports, imports and md5. The order and number of tuples + exports and md5. The order and number of tuples may change without prior notice.

- -

The {imports,Value} tuple may be removed in a future - release because Value is always an empty list. - Do not write code that depends on it being present.

@@ -272,12 +268,6 @@ behaviour_info(callbacks) -> Callbacks. beam_lib(3).

- imports - -

Always return an empty list. The imports key may not - be supported in future release.

-
- md5

Return a binary representing the MD5 checksum of the module.

-- cgit v1.2.3