mirror of
https://github.com/Mercury-Language/mercury.git
synced 2025-12-12 12:26:29 +00:00
Add support for demangling code produced by the MLDS back-end.
Estimated hours taken: 16 Branches: main util/mdemangle.c: profiler/demangle.m: Add support for demangling code produced by the MLDS back-end. XXX util/mdemangle.c it doesn't handle internal labels yet tests/misc_tests/Mmakefile: tests/misc_tests/mdemangle_test_hl.inp: tests/misc_tests/mdemangle_test_hl.exp: Add a test case. The test is not enabled, since we don't yet pass it; demangling works OK for many cases, but fails for cases involving internal labels.
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
%-----------------------------------------------------------------------------%
|
||||
% Copyright (C) 1997-2001 The University of Melbourne.
|
||||
% Copyright (C) 1997-2002 The University of Melbourne.
|
||||
% This file may only be copied under the terms of the GNU General
|
||||
% Public License - see the file COPYING in the Mercury distribution.
|
||||
%-----------------------------------------------------------------------------%
|
||||
@@ -73,7 +73,9 @@ demangle_from_asm -->
|
||||
:- pred demangle_from_c(string, string).
|
||||
:- mode demangle_from_c(in, out) is semidet.
|
||||
demangle_from_c -->
|
||||
( demangle_proc ->
|
||||
( demangle_proc_hl ->
|
||||
{ true }
|
||||
; demangle_proc_ll ->
|
||||
{ true }
|
||||
; demangle_data ->
|
||||
{ true }
|
||||
@@ -85,9 +87,9 @@ demangle_from_c -->
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
:- pred demangle_proc(string, string).
|
||||
:- mode demangle_proc(in, out) is semidet.
|
||||
demangle_proc -->
|
||||
:- pred demangle_proc_ll(string, string).
|
||||
:- mode demangle_proc_ll(in, out) is semidet.
|
||||
demangle_proc_ll -->
|
||||
remove_prefix("mercury__"),
|
||||
|
||||
%
|
||||
@@ -134,19 +136,7 @@ demangle_proc -->
|
||||
% set the `category' to the appropriate value and then
|
||||
% skip past the prefix.
|
||||
%
|
||||
( remove_prefix("__Unify__") ->
|
||||
{ Category0 = unify }
|
||||
; remove_prefix("__Compare__") ->
|
||||
{ Category0 = compare },
|
||||
% there should only be one mode for compare/3 preds
|
||||
{ ModeNum0 = 0 }
|
||||
; remove_prefix("__Index__") ->
|
||||
{ Category0 = index },
|
||||
% there should only be one mode for index/2 preds
|
||||
{ ModeNum0 = 0 }
|
||||
;
|
||||
{ Category0 = ordinary }
|
||||
),
|
||||
handle_compiler_generated_pred(ModeNum0, Category0),
|
||||
|
||||
%
|
||||
% Fix any ascii codes mangled in the predicate name
|
||||
@@ -154,47 +144,19 @@ demangle_proc -->
|
||||
fix_mangled_ascii,
|
||||
|
||||
%
|
||||
% Process the mangling introduced by unused_args.m.
|
||||
% This involves stripping off the `__ua<m>' or `__uab<m>' added to
|
||||
% the end of the predicate/function name, where m is the mode number.
|
||||
% Process the mangling introduced by unused_args.m
|
||||
% and higher_order.m.
|
||||
% This involves stripping off the `__ua<m>', `__uab<m>',
|
||||
% and/or `__ho<n>' added to the end of the
|
||||
% predicate/function name, where m is the mode number.
|
||||
%
|
||||
(
|
||||
remove_trailing_int(UA_ModeNum),
|
||||
m_remove_suffix("__ua")
|
||||
->
|
||||
{ UnusedArgs = yes(ModeNum0 - no) },
|
||||
{ ModeNum1 is UA_ModeNum mod 10000 }
|
||||
;
|
||||
remove_trailing_int(UA_ModeNum),
|
||||
m_remove_suffix("__uab")
|
||||
->
|
||||
{ UnusedArgs = yes(ModeNum0 - yes) },
|
||||
{ ModeNum1 is UA_ModeNum mod 10000 }
|
||||
;
|
||||
{ UnusedArgs = no },
|
||||
{ ModeNum1 = ModeNum0 }
|
||||
),
|
||||
|
||||
%
|
||||
% Process the mangling introduced by higher_order.m.
|
||||
% This involves stripping off the `__ho<n>' where
|
||||
% n is a unique identifier for this specialized version
|
||||
%
|
||||
(
|
||||
remove_trailing_int(HO_Num),
|
||||
m_remove_suffix("__ho")
|
||||
->
|
||||
{ HigherOrder = yes(HO_Num) }
|
||||
;
|
||||
{ HigherOrder = no }
|
||||
),
|
||||
{ ModeNum = ModeNum1 },
|
||||
demangle_unused_args(UnusedArgs, ModeNum0, ModeNum1),
|
||||
demangle_higher_order(HigherOrder, ModeNum1, ModeNum),
|
||||
|
||||
%
|
||||
% Make sure special predicates with unused_args
|
||||
% are reported correctly.
|
||||
%
|
||||
|
||||
( { UnusedArgs = yes(_), Category0 \= ordinary } ->
|
||||
remove_trailing_int(Arity)
|
||||
;
|
||||
@@ -217,9 +179,251 @@ demangle_proc -->
|
||||
"AccFrom__", "TypeSpecOf__"])
|
||||
),
|
||||
|
||||
% Remove any prefixes added for introduced predicates,
|
||||
% and get the predicate name.
|
||||
handle_category_etc(PredName, Category0, Category),
|
||||
|
||||
%
|
||||
% Now we need to look at the pred name and see if it is an
|
||||
% introduced lambda predicate.
|
||||
% Now, finally, we can construct the demangled symbol name
|
||||
%
|
||||
{ format_proc(Category, MaybeModule, PredOrFunc, PredName,
|
||||
Arity, ModeNum, HigherOrder, UnusedArgs, MaybeInternalLabelNum,
|
||||
Parts, []) },
|
||||
{ string__append_list(Parts, DemangledName) },
|
||||
dcg_set(DemangledName).
|
||||
|
||||
:- pred demangle_proc_hl(string, string).
|
||||
:- mode demangle_proc_hl(in, out) is semidet.
|
||||
demangle_proc_hl -->
|
||||
% Symbols in the Mercury standard library get an additional
|
||||
% "mercury__" prefix in their mangled name.
|
||||
maybe_remove_prefix("mercury__"),
|
||||
|
||||
%
|
||||
% Get integer from end of string (it might be the mode number,
|
||||
% it might be the internal label number).
|
||||
%
|
||||
remove_trailing_int(Int),
|
||||
(
|
||||
%
|
||||
% if we got to another int, that means it is an internal
|
||||
% label of the form `append_3_p_0_1'
|
||||
% in that case, save the internal label number and then
|
||||
% get the mode number
|
||||
%
|
||||
m_remove_suffix("_"),
|
||||
remove_trailing_int(ModeNum0)
|
||||
->
|
||||
{ ModeNum1 = ModeNum0 },
|
||||
{ MaybeInternalLabelNum0 = yes(Int) }
|
||||
;
|
||||
{ ModeNum1 = Int },
|
||||
{ MaybeInternalLabelNum0 = no }
|
||||
),
|
||||
|
||||
%
|
||||
% Handle the "f_" or "p_" suffix which indicates whether
|
||||
% the procedure is a function or a predicate
|
||||
%
|
||||
( m_remove_suffix("f_") ->
|
||||
{ PredOrFunc = "function" },
|
||||
{ Normal = yes }
|
||||
; m_remove_suffix("p_") ->
|
||||
{ PredOrFunc = "predicate" },
|
||||
{ Normal = yes }
|
||||
;
|
||||
% it could be a compiler-generated unify or compare predicate
|
||||
{ PredOrFunc = "predicate" },
|
||||
{ Normal = no }
|
||||
),
|
||||
|
||||
(
|
||||
%
|
||||
% Scan back past the arity number and then parse it.
|
||||
%
|
||||
m_remove_suffix("_"),
|
||||
remove_trailing_int(Arity0)
|
||||
->
|
||||
{ Arity = Arity0 },
|
||||
{ ModeNum2 = ModeNum1 },
|
||||
{ MaybeInternalLabelNum = MaybeInternalLabelNum0 }
|
||||
;
|
||||
% It must be a compiler-generated unify or compare.
|
||||
% What we thought were the mode number and label number
|
||||
% were actually the arity and mode number
|
||||
{ Normal = no },
|
||||
{ Arity = ModeNum1 },
|
||||
{ yes(ModeNum2) = MaybeInternalLabelNum0 },
|
||||
{ MaybeInternalLabelNum = no }
|
||||
),
|
||||
m_remove_suffix("_"),
|
||||
|
||||
%
|
||||
% Process the mangling introduced by unused_args.m
|
||||
% and higher_order.m.
|
||||
% This involves stripping off the `__ua<m>', `__uab<m>',
|
||||
% and/or `__ho<n>' added to the end of the
|
||||
% predicate/function name, where m is the mode number.
|
||||
%
|
||||
demangle_unused_args(UnusedArgs, ModeNum2, ModeNum3),
|
||||
demangle_higher_order(HigherOrder, ModeNum3, ModeNum),
|
||||
|
||||
%
|
||||
% Make sure special predicates with unused_args
|
||||
% are reported correctly.
|
||||
%
|
||||
|
||||
( { UnusedArgs = yes(_), Normal = no } ->
|
||||
remove_trailing_int(Arity)
|
||||
;
|
||||
{ true }
|
||||
),
|
||||
|
||||
%
|
||||
% Separate the module name from the predicate name
|
||||
%
|
||||
remove_maybe_module_prefix(MaybeModule0,
|
||||
["IntroducedFrom__", "DeforestationIn__",
|
||||
"AccFrom__", "TypeSpecOf__", "__"]),
|
||||
|
||||
%
|
||||
% Check whether the start of the string matches the name of
|
||||
% one of the special compiler-generated predicates; if so,
|
||||
% set the `category' to the appropriate value and then
|
||||
% skip past the prefix. Also check that the mode number
|
||||
% is not invalid for the specified category.
|
||||
%
|
||||
handle_compiler_generated_pred(ModeNum, Category0),
|
||||
( { Category0 \= ordinary } ->
|
||||
remove_prefix("__")
|
||||
;
|
||||
[]
|
||||
),
|
||||
|
||||
%
|
||||
% Check that the setting of the category matches the setting
|
||||
% of `Normal' determined above.
|
||||
%
|
||||
{ Normal = yes, Category0 = ordinary
|
||||
; Normal = no, Category0 \= ordinary
|
||||
},
|
||||
|
||||
%
|
||||
% Fix any mangled ascii codes in the predicate name.
|
||||
%
|
||||
% XXX This should be done *before* stripping off
|
||||
% the mangling added by HLDS->HLDS passes such as
|
||||
% unused_args.m and higher_order.m.
|
||||
% (Doing it here means that we won't properly demangle
|
||||
% names that involve both special characters and
|
||||
% unused_args/higher_order specializations.)
|
||||
% But for the MLDS back-end, it needs to be done *after*
|
||||
% removing the module prefix, and currently that can't be
|
||||
% done until after stripping off the `__ua*' and `__ho*' suffixes.
|
||||
%
|
||||
fix_mangled_ascii,
|
||||
|
||||
%
|
||||
% Fix any mangled ascii codes in the module name, if any.
|
||||
%
|
||||
{
|
||||
MaybeModule0 = no,
|
||||
MaybeModule = no
|
||||
;
|
||||
MaybeModule0 = yes(ModuleName0),
|
||||
fix_mangled_ascii(ModuleName0, ModuleName),
|
||||
MaybeModule = yes(ModuleName)
|
||||
},
|
||||
|
||||
% Remove any prefixes added for introduced predicates,
|
||||
% and get the predicate name.
|
||||
handle_category_etc(PredName, Category0, Category),
|
||||
|
||||
%
|
||||
% Now, finally, we can construct the demangled symbol name
|
||||
%
|
||||
{ format_proc(Category, MaybeModule, PredOrFunc, PredName,
|
||||
Arity, ModeNum, HigherOrder, UnusedArgs, MaybeInternalLabelNum,
|
||||
Parts, []) },
|
||||
{ string__append_list(Parts, DemangledName) },
|
||||
dcg_set(DemangledName).
|
||||
|
||||
|
||||
:- pred demangle_unused_args(maybe(pair(int, bool)), int, int, string, string).
|
||||
:- mode demangle_unused_args(out, in, out, in, out) is det.
|
||||
demangle_unused_args(UnusedArgs, ModeNum0, ModeNum) -->
|
||||
%
|
||||
% Process the mangling introduced by unused_args.m.
|
||||
% This involves stripping off the `__ua<m>' or `__uab<m>' added to
|
||||
% the end of the predicate/function name, where m is the mode number.
|
||||
%
|
||||
(
|
||||
remove_trailing_int(UA_ModeNum),
|
||||
m_remove_suffix("__ua")
|
||||
->
|
||||
{ UnusedArgs = yes(ModeNum0 - no) },
|
||||
{ ModeNum is UA_ModeNum mod 10000 }
|
||||
;
|
||||
remove_trailing_int(UA_ModeNum),
|
||||
m_remove_suffix("__uab")
|
||||
->
|
||||
{ UnusedArgs = yes(ModeNum0 - yes) },
|
||||
{ ModeNum is UA_ModeNum mod 10000 }
|
||||
;
|
||||
{ UnusedArgs = no },
|
||||
{ ModeNum = ModeNum0 }
|
||||
).
|
||||
|
||||
:- pred demangle_higher_order(maybe(int), int, int, string, string).
|
||||
:- mode demangle_higher_order(out, in, out, in, out) is det.
|
||||
demangle_higher_order(HigherOrder, ModeNum0, ModeNum) -->
|
||||
%
|
||||
% Process the mangling introduced by higher_order.m.
|
||||
% This involves stripping off the `__ho<n>' where
|
||||
% n is a unique identifier for this specialized version
|
||||
%
|
||||
(
|
||||
remove_trailing_int(HO_Num),
|
||||
m_remove_suffix("__ho")
|
||||
->
|
||||
{ HigherOrder = yes(HO_Num) }
|
||||
;
|
||||
{ HigherOrder = no }
|
||||
),
|
||||
{ ModeNum = ModeNum0 }.
|
||||
|
||||
%
|
||||
% Check whether the start of the string matches the name of
|
||||
% one of the special compiler-generated predicates; if so,
|
||||
% set the category to the appropriate value and then
|
||||
% skip past the prefix. Fails if the mode number
|
||||
% is invalid for the specified category.
|
||||
%
|
||||
:- pred handle_compiler_generated_pred(int, pred_category, string, string).
|
||||
:- mode handle_compiler_generated_pred(in, out, in, out) is semidet.
|
||||
handle_compiler_generated_pred(ModeNum0, Category0) -->
|
||||
( remove_prefix("__Unify__") ->
|
||||
{ Category0 = unify }
|
||||
; remove_prefix("__Compare__") ->
|
||||
{ Category0 = compare },
|
||||
% there should only be one mode for compare/3 preds
|
||||
{ ModeNum0 = 0 }
|
||||
; remove_prefix("__Index__") ->
|
||||
{ Category0 = index },
|
||||
% there should only be one mode for index/2 preds
|
||||
{ ModeNum0 = 0 }
|
||||
;
|
||||
{ Category0 = ordinary }
|
||||
).
|
||||
|
||||
% Remove any prefixes added for introduced predicates,
|
||||
% and get the predicate name.
|
||||
:- pred handle_category_etc(string, pred_category, pred_category, string, string).
|
||||
:- mode handle_category_etc(out, in, out, in, out) is semidet.
|
||||
handle_category_etc(PredName, Category0, Category) -->
|
||||
%
|
||||
% we need to look at the pred name and see if it is an
|
||||
% introduced predicate (lambda, deforestation, accumulator, etc.).
|
||||
% XXX handle multiple prefixes
|
||||
%
|
||||
|
||||
@@ -297,17 +501,7 @@ demangle_proc -->
|
||||
;
|
||||
{ Category = Category0 },
|
||||
{ PredName = PredName0 }
|
||||
),
|
||||
|
||||
|
||||
%
|
||||
% Now, finally, we can construct the demangled symbol name
|
||||
%
|
||||
{ format_proc(Category, MaybeModule, PredOrFunc, PredName,
|
||||
Arity, ModeNum, HigherOrder, UnusedArgs, MaybeInternalLabelNum,
|
||||
Parts, []) },
|
||||
{ string__append_list(Parts, DemangledName) },
|
||||
dcg_set(DemangledName).
|
||||
).
|
||||
|
||||
:- pred format_proc(pred_category, maybe(string), string, string, int, int,
|
||||
maybe(int), maybe(pair(int, bool)), maybe(int), list(string),
|
||||
@@ -400,12 +594,28 @@ format_proc(Category, MaybeModule, PredOrFunc, PredName, Arity, ModeNum,
|
||||
:- pred demangle_data(string, string).
|
||||
:- mode demangle_data(in, out) is semidet.
|
||||
demangle_data -->
|
||||
remove_prefix("mercury_data_"),
|
||||
( remove_prefix("mercury_data_") ->
|
||||
% LLDS mangled data
|
||||
{ HighLevel = no }
|
||||
;
|
||||
% MLDS mangled data
|
||||
{ HighLevel = yes },
|
||||
maybe_remove_prefix("mercury__")
|
||||
),
|
||||
remove_maybe_module_prefix(MaybeModule0,
|
||||
["type_ctor_info_", "type_ctor_layout_",
|
||||
"type_ctor_functors_", "common_"]),
|
||||
{ MaybeModule0 = yes("") ->
|
||||
MaybeModule = no
|
||||
;
|
||||
% for the MLDS back-end,
|
||||
% the module qualifiers get include twice (XXX why?)
|
||||
HighLevel = yes,
|
||||
MaybeModule0 = yes(Twice)
|
||||
->
|
||||
Once = string__left(Twice, string__length(Twice) // 2),
|
||||
Once = string__right(Twice, string__length(Twice) // 2),
|
||||
MaybeModule = yes(Once)
|
||||
;
|
||||
MaybeModule = MaybeModule0
|
||||
},
|
||||
@@ -471,8 +681,8 @@ format_data(common, MaybeModule, _Name, Arity, Result) :-
|
||||
:- pred demangle_typeclass_info(string, string).
|
||||
:- mode demangle_typeclass_info(in, out) is semidet.
|
||||
demangle_typeclass_info -->
|
||||
remove_prefix("mercury_data_"),
|
||||
remove_prefix("__base_typeclass_info_"),
|
||||
maybe_remove_prefix("mercury_data___"),
|
||||
remove_prefix("base_typeclass_info_"),
|
||||
remove_maybe_module_prefix(yes(ClassName), ["arity"]),
|
||||
{ ClassName \= "" },
|
||||
remove_prefix("arity"),
|
||||
|
||||
@@ -5,6 +5,9 @@ THIS_DIR = misc_tests
|
||||
SUBDIRS =
|
||||
PROGS =
|
||||
TESTS = mdemangle_test-nodepend pretty_print_test-nodepend
|
||||
# XXX we do not yet pass mdemangle_test_hl
|
||||
# (util/mdemangle.c doesn't correctly demangle internal labels)
|
||||
# TESTS += mdemangle_test_hl-nodepend
|
||||
TESTS_DIR=..
|
||||
include $(TESTS_DIR)/Mmake.common
|
||||
|
||||
@@ -19,6 +22,9 @@ include Mercury.options
|
||||
mdemangle_test.out: mdemangle_test.inp
|
||||
mdemangle < mdemangle_test.inp > mdemangle_test.out 2>&1
|
||||
|
||||
mdemangle_test_hl.out: mdemangle_test_hl.inp
|
||||
mdemangle < mdemangle_test_hl.inp > mdemangle_test_hl.out 2>&1
|
||||
|
||||
pretty_print_test.out: pretty_print_test.ugly
|
||||
cp pretty_print_test.ugly pretty_print_test.out
|
||||
|
||||
@@ -27,6 +33,9 @@ pretty_print_test.out: pretty_print_test.ugly
|
||||
mdemangle_test.realclean:
|
||||
rm -f mdemangle_test.out mdemangle_test.res
|
||||
|
||||
mdemangle_test_hl.realclean:
|
||||
rm -f mdemangle_test_hl.out mdemangle_test_hl.res
|
||||
|
||||
pretty_print_test.realclean:
|
||||
rm -f pretty_print_test.ugly pretty_print_test.out
|
||||
rm -f pretty_print_test.res
|
||||
|
||||
140
tests/misc_tests/mdemangle_test_hl.exp
Normal file
140
tests/misc_tests/mdemangle_test_hl.exp
Normal file
@@ -0,0 +1,140 @@
|
||||
A collection of symbols for use in testing mdemangle.
|
||||
This file tests demangling of symbols generated by the MLDS (--high-level-code) back-end.
|
||||
|
||||
Each symbol is followed by the correct decoding.
|
||||
|
||||
a type ctor info
|
||||
<type_ctor_info for type 'builtin:int'/0>
|
||||
<type_ctor_info for type 'builtin:int'/0>
|
||||
|
||||
a nested module type ctor info
|
||||
<type_ctor_info for type 'mdb:util:trace_port_type'/0>
|
||||
<type_ctor_info for type 'mdb:util:trace_port_type'/0>
|
||||
|
||||
a type ctor layout
|
||||
the MLDS back-end doesn't generate these yet
|
||||
|
||||
a type ctor functors
|
||||
the MLDS back-end doesn't generate these yet
|
||||
|
||||
a mangled name
|
||||
<predicate 'foo:!'/0 mode 0>
|
||||
<predicate 'foo:!'/0 mode 0>
|
||||
|
||||
a compare predicate
|
||||
<compare/3 predicate for type 'list:list'/1>
|
||||
<compare/3 predicate for type 'list:list'/1>
|
||||
|
||||
an index predicate
|
||||
<index/2 predicate for type 'list:list'/1>
|
||||
<index/2 predicate for type 'list:list'/1>
|
||||
|
||||
a unify predicate
|
||||
<unification predicate for type 'list:list'/1 mode 0>
|
||||
<unification predicate for type 'list:list'/1 mode 0>
|
||||
|
||||
a normal predicate
|
||||
<predicate 'list:append'/3 mode 0>
|
||||
<predicate 'list:append'/3 mode 0>
|
||||
|
||||
a function
|
||||
<function 'list:append'/2 mode 0>
|
||||
<function 'list:append'/2 mode 0>
|
||||
|
||||
an internal label
|
||||
<predicate 'list:append'/3 mode 4 label 1>
|
||||
<predicate 'list:append'/3 mode 4 label 1>
|
||||
|
||||
unused args
|
||||
XXX need to test this
|
||||
|
||||
higher order specialization
|
||||
<function 'higher_order_func_test:my_map'/3 mode 0 (specialized [#3])>
|
||||
<function 'higher_order_func_test:my_map'/3 mode 0 (specialized [#3])>
|
||||
|
||||
higher order specialization (regression test for 1 char pred names)
|
||||
<function 'higher_order_func_test:c'/3 mode 0 (specialized [#3])>
|
||||
<function 'higher_order_func_test:c'/3 mode 0 (specialized [#3])>
|
||||
|
||||
higher order specialization and unused args
|
||||
<function 'higher_order_func_test:c'/3 mode 1 (specialized [#3]) (minus unused args [#0])>
|
||||
<function 'higher_order_func_test:c'/3 mode 1 (specialized [#3]) (minus unused args [#0])>
|
||||
|
||||
mangled name with unused args
|
||||
(XXX TODO)
|
||||
|
||||
some tests of symbols that should not be demangled
|
||||
(this is a regression test: previous versions of mdemangle
|
||||
seg faulted for this case)
|
||||
mercury_data_foo
|
||||
mercury_data_foo
|
||||
|
||||
some lambda goals
|
||||
(XXX TODO)
|
||||
<pred goal (#9) from 'simplex' in module 'lp' line 262 label 5>
|
||||
<pred goal (#9) from 'simplex' in module 'lp' line 262 label 5>
|
||||
<func goal (#4) from 'collect_vars' in module 'lp' line 153>
|
||||
<func goal (#4) from 'collect_vars' in module 'lp' line 153>
|
||||
|
||||
procedures introduced by deforestation
|
||||
(XXX TODO)
|
||||
<deforestation procedure (#9) from 'simplex' in module 'lp' line 262 label 5>
|
||||
<deforestation procedure (#9) from 'simplex' in module 'lp' line 262 label 5>
|
||||
<deforestation procedure (#4) from 'collect_vars' in module 'lp' line 153>
|
||||
<deforestation procedure (#4) from 'collect_vars' in module 'lp' line 153>
|
||||
|
||||
procedure introduced by type specialization
|
||||
(XXX TODO)
|
||||
<function 'sparse_bitset:list_to_set'/1 mode 0 (type specialized [T = var(V_2)])>
|
||||
<function 'sparse_bitset:list_to_set'/1 mode 0 (type specialized [T = var(V_2)])>
|
||||
|
||||
type specialization and deforestion
|
||||
(XXX TODO)
|
||||
XXX this needs to be fixed
|
||||
<predicate 'doubleapp_impl:DeforestationIn__pred__TypeSpecOf__pred_or_func__double_app__[T = int]__21__0'/5 mode 0 (minus unused args [#0])>
|
||||
<predicate 'doubleapp_impl:DeforestationIn__pred__TypeSpecOf__pred_or_func__double_app__[T = int]__21__0'/5 mode 0 (minus unused args [#0])>
|
||||
|
||||
A realistic test
|
||||
|
||||
/usr/lib/crt1.o: In function `_start':
|
||||
/usr/lib/crt1.o(.text+0x18): undefined reference to `main'
|
||||
interpreter.o: In function `<predicate 'interpreter:deref'/4 mode 0>':
|
||||
interpreter.o(.text+0xcb1): undefined reference to `<predicate 'tr_store:get_mutvar'/4 mode 0>'
|
||||
interpreter.o: In function `<predicate 'interpreter:not_occurs'/4 mode 0>':
|
||||
interpreter.o(.text+0xdcc): undefined reference to `<predicate 'tr_store:get_mutvar'/4 mode 0>'
|
||||
interpreter.o: In function `<predicate 'interpreter:unify'/4 mode 0>':
|
||||
interpreter.o(.text+0xed4): undefined reference to `<predicate 'tr_store:get_mutvar'/4 mode 0>'
|
||||
interpreter.o(.text+0xf01): undefined reference to `<predicate 'tr_store:get_mutvar'/4 mode 0>'
|
||||
interpreter.o(.text+0x10bb): undefined reference to `<predicate 'tr_store:set_mutvar'/4 mode 0>'
|
||||
interpreter.o(.text+0x10fa): undefined reference to `<predicate 'tr_store:get_mutvar'/4 mode 0>'
|
||||
interpreter.o(.text+0x117a): undefined reference to `<predicate 'tr_store:get_mutvar'/4 mode 0>'
|
||||
interpreter.o(.text+0x11ba): undefined reference to `<predicate 'tr_store:set_mutvar'/4 mode 0>'
|
||||
interpreter.o: In function `<predicate 'interpreter:my_term_to_term'/8 mode 0>':
|
||||
interpreter.o(.text+0x192e): undefined reference to `<predicate 'tr_store:get_mutvar'/4 mode 0>'
|
||||
interpreter.o: In function `<predicate 'interpreter:term_to_my_term'/6 mode 0>':
|
||||
interpreter.o(.text+0x1b97): undefined reference to `<predicate 'tr_store:new_mutvar'/4 mode 0>'
|
||||
interpreter.o: In function `<predicate 'interpreter:main_loop_2'/4 mode 0 label 2>':
|
||||
interpreter.o(.text+0x2146): undefined reference to `<predicate 'unsafe:unsafe_perform_io'/1 mode 0>'
|
||||
collect2: ld returned 1 exit status
|
||||
|
||||
/usr/lib/crt1.o: In function `_start':
|
||||
/usr/lib/crt1.o(.text+0x18): undefined reference to `main'
|
||||
interpreter.o: In function `<predicate 'interpreter:deref'/4 mode 0>':
|
||||
interpreter.o(.text+0xcb1): undefined reference to `<predicate 'tr_store:get_mutvar'/4 mode 0>'
|
||||
interpreter.o: In function `<predicate 'interpreter:not_occurs'/4 mode 0>':
|
||||
interpreter.o(.text+0xdcc): undefined reference to `<predicate 'tr_store:get_mutvar'/4 mode 0>'
|
||||
interpreter.o: In function `<predicate 'interpreter:unify'/4 mode 0>':
|
||||
interpreter.o(.text+0xed4): undefined reference to `<predicate 'tr_store:get_mutvar'/4 mode 0>'
|
||||
interpreter.o(.text+0xf01): undefined reference to `<predicate 'tr_store:get_mutvar'/4 mode 0>'
|
||||
interpreter.o(.text+0x10bb): undefined reference to `<predicate 'tr_store:set_mutvar'/4 mode 0>'
|
||||
interpreter.o(.text+0x10fa): undefined reference to `<predicate 'tr_store:get_mutvar'/4 mode 0>'
|
||||
interpreter.o(.text+0x117a): undefined reference to `<predicate 'tr_store:get_mutvar'/4 mode 0>'
|
||||
interpreter.o(.text+0x11ba): undefined reference to `<predicate 'tr_store:set_mutvar'/4 mode 0>'
|
||||
interpreter.o: In function `<predicate 'interpreter:my_term_to_term'/8 mode 0>':
|
||||
interpreter.o(.text+0x192e): undefined reference to `<predicate 'tr_store:get_mutvar'/4 mode 0>'
|
||||
interpreter.o: In function `<predicate 'interpreter:term_to_my_term'/6 mode 0>':
|
||||
interpreter.o(.text+0x1b97): undefined reference to `<predicate 'tr_store:new_mutvar'/4 mode 0>'
|
||||
interpreter.o: In function `<predicate 'interpreter:main_loop_2'/4 mode 0 label 2>':
|
||||
interpreter.o(.text+0x2146): undefined reference to `<predicate 'unsafe:unsafe_perform_io'/1 mode 0>'
|
||||
collect2: ld returned 1 exit status
|
||||
|
||||
140
tests/misc_tests/mdemangle_test_hl.inp
Normal file
140
tests/misc_tests/mdemangle_test_hl.inp
Normal file
@@ -0,0 +1,140 @@
|
||||
A collection of symbols for use in testing mdemangle.
|
||||
This file tests demangling of symbols generated by the MLDS (--high-level-code) back-end.
|
||||
|
||||
Each symbol is followed by the correct decoding.
|
||||
|
||||
a type ctor info
|
||||
mercury__builtin__builtin__type_ctor_info_int_0
|
||||
<type_ctor_info for type 'builtin:int'/0>
|
||||
|
||||
a nested module type ctor info
|
||||
mdb__util__mdb__util__type_ctor_info_trace_port_type_0
|
||||
<type_ctor_info for type 'mdb:util:trace_port_type'/0>
|
||||
|
||||
a type ctor layout
|
||||
the MLDS back-end doesn't generate these yet
|
||||
|
||||
a type ctor functors
|
||||
the MLDS back-end doesn't generate these yet
|
||||
|
||||
a mangled name
|
||||
foo__f_cut_0_p_0
|
||||
<predicate 'foo:!'/0 mode 0>
|
||||
|
||||
a compare predicate
|
||||
mercury__list____Compare____list_1_0
|
||||
<compare/3 predicate for type 'list:list'/1>
|
||||
|
||||
an index predicate
|
||||
mercury__list____Index____list_1_0
|
||||
<index/2 predicate for type 'list:list'/1>
|
||||
|
||||
a unify predicate
|
||||
mercury__list____Unify____list_1_0
|
||||
<unification predicate for type 'list:list'/1 mode 0>
|
||||
|
||||
a normal predicate
|
||||
mercury__list__append_3_p_0
|
||||
<predicate 'list:append'/3 mode 0>
|
||||
|
||||
a function
|
||||
mercury__list__append_2_f_0
|
||||
<function 'list:append'/2 mode 0>
|
||||
|
||||
an internal label
|
||||
mercury__list__append_3_p_4_1
|
||||
<predicate 'list:append'/3 mode 4 label 1>
|
||||
|
||||
unused args
|
||||
XXX need to test this
|
||||
|
||||
higher order specialization
|
||||
higher_order_func_test__my_map__ho3_3_f_0
|
||||
<function 'higher_order_func_test:my_map'/3 mode 0 (specialized [#3])>
|
||||
|
||||
higher order specialization (regression test for 1 char pred names)
|
||||
higher_order_func_test__c__ho3_3_f_0
|
||||
<function 'higher_order_func_test:c'/3 mode 0 (specialized [#3])>
|
||||
|
||||
higher order specialization and unused args
|
||||
higher_order_func_test__c__ho3__ua1_3_f_0
|
||||
<function 'higher_order_func_test:c'/3 mode 1 (specialized [#3]) (minus unused args [#0])>
|
||||
|
||||
mangled name with unused args
|
||||
(XXX TODO)
|
||||
|
||||
some tests of symbols that should not be demangled
|
||||
(this is a regression test: previous versions of mdemangle
|
||||
seg faulted for this case)
|
||||
mercury_data_foo
|
||||
mercury_data_foo
|
||||
|
||||
some lambda goals
|
||||
(XXX TODO)
|
||||
mercury__lp__IntroducedFrom__pred__simplex__262__9_7_0_i5
|
||||
<pred goal (#9) from 'simplex' in module 'lp' line 262 label 5>
|
||||
mercury__lp__IntroducedFrom__func__collect_vars__153__4_3_0
|
||||
<func goal (#4) from 'collect_vars' in module 'lp' line 153>
|
||||
|
||||
procedures introduced by deforestation
|
||||
(XXX TODO)
|
||||
mercury__lp__DeforestationIn__pred__simplex__262__9_7_0_i5
|
||||
<deforestation procedure (#9) from 'simplex' in module 'lp' line 262 label 5>
|
||||
mercury__lp__DeforestationIn__pred__collect_vars__153__4_3_0
|
||||
<deforestation procedure (#4) from 'collect_vars' in module 'lp' line 153>
|
||||
|
||||
procedure introduced by type specialization
|
||||
(XXX TODO)
|
||||
mercury__fn__f_115_112_97_114_115_101_95_98_105_116_115_101_116_95_95_84_121_112_101_83_112_101_99_79_102_95_95_112_114_101_100_95_111_114_95_102_117_110_99_95_95_108_105_115_116_95_116_111_95_115_101_116_95_95_91_84_32_61_32_118_97_114_40_86_95_50_41_93_95_48_95_49_1_0
|
||||
<function 'sparse_bitset:list_to_set'/1 mode 0 (type specialized [T = var(V_2)])>
|
||||
|
||||
type specialization and deforestion
|
||||
(XXX TODO)
|
||||
XXX this needs to be fixed
|
||||
mercury__f_100_111_117_98_108_101_97_112_112_95_105_109_112_108_95_95_68_101_102_111_114_101_115_116_97_116_105_111_110_73_110_95_95_112_114_101_100_95_95_84_121_112_101_83_112_101_99_79_102_95_95_112_114_101_100_95_111_114_95_102_117_110_99_95_95_100_111_117_98_108_101_95_97_112_112_95_95_91_84_32_61_32_105_110_116_93_95_95_50_49_95_95_48_95_95_117_97_48_5_0
|
||||
<predicate 'doubleapp_impl:DeforestationIn__pred__TypeSpecOf__pred_or_func__double_app__[T = int]__21__0'/5 mode 0 (minus unused args [#0])>
|
||||
|
||||
A realistic test
|
||||
|
||||
/usr/lib/crt1.o: In function `_start':
|
||||
/usr/lib/crt1.o(.text+0x18): undefined reference to `main'
|
||||
interpreter.o: In function `interpreter__deref_4_p_0':
|
||||
interpreter.o(.text+0xcb1): undefined reference to `tr_store__get_mutvar_4_p_0'
|
||||
interpreter.o: In function `interpreter__not_occurs_4_p_0':
|
||||
interpreter.o(.text+0xdcc): undefined reference to `tr_store__get_mutvar_4_p_0'
|
||||
interpreter.o: In function `interpreter__unify_4_p_0':
|
||||
interpreter.o(.text+0xed4): undefined reference to `tr_store__get_mutvar_4_p_0'
|
||||
interpreter.o(.text+0xf01): undefined reference to `tr_store__get_mutvar_4_p_0'
|
||||
interpreter.o(.text+0x10bb): undefined reference to `tr_store__set_mutvar_4_p_0'
|
||||
interpreter.o(.text+0x10fa): undefined reference to `tr_store__get_mutvar_4_p_0'
|
||||
interpreter.o(.text+0x117a): undefined reference to `tr_store__get_mutvar_4_p_0'
|
||||
interpreter.o(.text+0x11ba): undefined reference to `tr_store__set_mutvar_4_p_0'
|
||||
interpreter.o: In function `interpreter__my_term_to_term_8_p_0':
|
||||
interpreter.o(.text+0x192e): undefined reference to `tr_store__get_mutvar_4_p_0'
|
||||
interpreter.o: In function `interpreter__term_to_my_term_6_p_0':
|
||||
interpreter.o(.text+0x1b97): undefined reference to `tr_store__new_mutvar_4_p_0'
|
||||
interpreter.o: In function `interpreter__main_loop_2_4_p_0_2':
|
||||
interpreter.o(.text+0x2146): undefined reference to `unsafe__unsafe_perform_io_1_p_0'
|
||||
collect2: ld returned 1 exit status
|
||||
|
||||
/usr/lib/crt1.o: In function `_start':
|
||||
/usr/lib/crt1.o(.text+0x18): undefined reference to `main'
|
||||
interpreter.o: In function `<predicate 'interpreter:deref'/4 mode 0>':
|
||||
interpreter.o(.text+0xcb1): undefined reference to `<predicate 'tr_store:get_mutvar'/4 mode 0>'
|
||||
interpreter.o: In function `<predicate 'interpreter:not_occurs'/4 mode 0>':
|
||||
interpreter.o(.text+0xdcc): undefined reference to `<predicate 'tr_store:get_mutvar'/4 mode 0>'
|
||||
interpreter.o: In function `<predicate 'interpreter:unify'/4 mode 0>':
|
||||
interpreter.o(.text+0xed4): undefined reference to `<predicate 'tr_store:get_mutvar'/4 mode 0>'
|
||||
interpreter.o(.text+0xf01): undefined reference to `<predicate 'tr_store:get_mutvar'/4 mode 0>'
|
||||
interpreter.o(.text+0x10bb): undefined reference to `<predicate 'tr_store:set_mutvar'/4 mode 0>'
|
||||
interpreter.o(.text+0x10fa): undefined reference to `<predicate 'tr_store:get_mutvar'/4 mode 0>'
|
||||
interpreter.o(.text+0x117a): undefined reference to `<predicate 'tr_store:get_mutvar'/4 mode 0>'
|
||||
interpreter.o(.text+0x11ba): undefined reference to `<predicate 'tr_store:set_mutvar'/4 mode 0>'
|
||||
interpreter.o: In function `<predicate 'interpreter:my_term_to_term'/8 mode 0>':
|
||||
interpreter.o(.text+0x192e): undefined reference to `<predicate 'tr_store:get_mutvar'/4 mode 0>'
|
||||
interpreter.o: In function `<predicate 'interpreter:term_to_my_term'/6 mode 0>':
|
||||
interpreter.o(.text+0x1b97): undefined reference to `<predicate 'tr_store:new_mutvar'/4 mode 0>'
|
||||
interpreter.o: In function `<predicate 'interpreter:main_loop_2'/4 mode 0 label 2>':
|
||||
interpreter.o(.text+0x2146): undefined reference to `<predicate 'unsafe:unsafe_perform_io'/1 mode 0>'
|
||||
collect2: ld returned 1 exit status
|
||||
|
||||
208
util/mdemangle.c
208
util/mdemangle.c
@@ -1,7 +1,7 @@
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
** Copyright (C) 1995-2001 The University of Melbourne.
|
||||
** Copyright (C) 1995-2002 The University of Melbourne.
|
||||
** This file may only be copied under the terms of the GNU General
|
||||
** Public License - see the file COPYING in the Mercury distribution.
|
||||
*/
|
||||
@@ -32,7 +32,7 @@
|
||||
|
||||
static void demangle(const char *name);
|
||||
static const char *strip_module_name(char **start_ptr, char *end,
|
||||
const char *trailing_context[]);
|
||||
const char *special_prefixes[], const char *special_suffixes[]);
|
||||
static MR_bool check_for_suffix(char *start, char *position,
|
||||
const char *suffix, int sizeof_suffix, int *mode_num2);
|
||||
static char *fix_mangled_ascii(char *str, char **end);
|
||||
@@ -43,6 +43,7 @@ static MR_bool cut_trailing_integer(char *str, char **end, int *num);
|
||||
static MR_bool cut_trailing_underscore_integer(char *str,
|
||||
char **end, int *num);
|
||||
static MR_bool strip_prefix(char **str, const char *prefix);
|
||||
static MR_bool strip_suffix(const char *str, char **end, const char *suffix);
|
||||
static MR_bool strip_leading_integer(char **start_ptr, int *num);
|
||||
|
||||
/*
|
||||
@@ -142,17 +143,18 @@ main(int argc, char **argv)
|
||||
** human-readable form and then print it to stdout
|
||||
*/
|
||||
|
||||
static void
|
||||
static void
|
||||
demangle(const char *orig_name)
|
||||
{
|
||||
static const char entry[] = "_entry_";
|
||||
static const char mercury[] = "mercury__";
|
||||
static const char func_prefix[] = "fn__"; /* added for functions */
|
||||
static const char unify[] = "__Unify___";
|
||||
static const char compare[] = "__Compare___";
|
||||
static const char mindex[] = "__Index___";
|
||||
/* we call it `mindex' rather than `index' to
|
||||
avoid a naming conflict with strchr's alter ego index() */
|
||||
static const char unify1[] = "__Unify___";
|
||||
static const char unify2[] = "__Unify____";
|
||||
static const char compare1[] = "__Compare___";
|
||||
static const char compare2[] = "__Compare____";
|
||||
static const char index1[] = "__Index___";
|
||||
static const char index2[] = "__Index____";
|
||||
|
||||
static const char introduced[] = "IntroducedFrom__";
|
||||
static const char deforestation[] = "DeforestationIn__";
|
||||
@@ -170,7 +172,9 @@ demangle(const char *orig_name)
|
||||
static const char type_ctor_layout[] = "type_ctor_layout_";
|
||||
static const char type_ctor_info[] = "type_ctor_info_";
|
||||
static const char type_ctor_functors[] = "type_ctor_functors_";
|
||||
static const char base_typeclass_info[] = "__base_typeclass_info_";
|
||||
static const char base_typeclass_info[] = "base_typeclass_info_";
|
||||
static const char underscores_base_typeclass_info[] =
|
||||
"__base_typeclass_info_";
|
||||
static const char common[] = "common";
|
||||
static const char arity_string[] = "arity";
|
||||
static const char underscores_arity_string[] = "__arity";
|
||||
@@ -183,8 +187,16 @@ demangle(const char *orig_name)
|
||||
deforestation,
|
||||
accumulator,
|
||||
type_spec,
|
||||
unify1, compare1, index1,
|
||||
NULL
|
||||
};
|
||||
static const char * trailing_context_1_hl_suffixes[] = {
|
||||
ua_suffix,
|
||||
ua_suffix2,
|
||||
ho_suffix,
|
||||
NULL
|
||||
};
|
||||
|
||||
|
||||
static const char * trailing_context_2[] = {
|
||||
type_ctor_layout,
|
||||
@@ -207,6 +219,8 @@ demangle(const char *orig_name)
|
||||
int mode_num;
|
||||
int mode_num2;
|
||||
int arity;
|
||||
MR_bool high_level = MR_TRUE;
|
||||
MR_bool matched = MR_FALSE;
|
||||
const char *pred_or_func; /* either "predicate" or "function" */
|
||||
/* does this proc have any unused arguments */
|
||||
MR_bool unused_args = MR_FALSE;
|
||||
@@ -271,26 +285,16 @@ demangle(const char *orig_name)
|
||||
strip_prefix(&start, entry);
|
||||
|
||||
/*
|
||||
** strip off the `mercury__' prefix
|
||||
** strip off the `mercury__' prefix, if any
|
||||
*/
|
||||
|
||||
if (!strip_prefix(&start, mercury)) {
|
||||
goto not_plain_mercury;
|
||||
if (strip_prefix(&start, mercury)) {
|
||||
matched = MR_TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
** Code for dealing with predicate symbols.
|
||||
*/
|
||||
|
||||
/*
|
||||
** strip off the `fn__' prefix, if any
|
||||
*/
|
||||
if (strip_prefix(&start, func_prefix)) {
|
||||
pred_or_func = "function";
|
||||
} else {
|
||||
pred_or_func = "predicate";
|
||||
}
|
||||
|
||||
/*
|
||||
** Get integer from end of string (it might be the mode number,
|
||||
** it might be the internal label number). We'll assume its mode
|
||||
@@ -298,10 +302,10 @@ demangle(const char *orig_name)
|
||||
*/
|
||||
|
||||
if (!cut_trailing_integer(start, &end, &mode_num)) {
|
||||
goto wrong_format;
|
||||
goto not_plain_mercury;
|
||||
}
|
||||
|
||||
if (end == start) goto wrong_format;
|
||||
if (end == start) goto not_plain_mercury;
|
||||
|
||||
/*
|
||||
** if we got to an `i', that means it is an internal
|
||||
@@ -311,21 +315,54 @@ demangle(const char *orig_name)
|
||||
*/
|
||||
if (*--end == 'i') {
|
||||
internal = mode_num;
|
||||
if (end == start || *--end != '_') goto wrong_format;
|
||||
if (end == start || *--end != '_') goto not_plain_mercury;
|
||||
|
||||
if (!cut_trailing_underscore_integer(start, &end, &mode_num)) {
|
||||
goto wrong_format;
|
||||
goto not_plain_mercury;
|
||||
}
|
||||
}
|
||||
if (end == start) goto not_plain_mercury;
|
||||
|
||||
/*
|
||||
** strip off the `fn__' prefix, if any
|
||||
*/
|
||||
if (strip_prefix(&start, func_prefix)) {
|
||||
high_level = MR_FALSE;
|
||||
pred_or_func = "function";
|
||||
} else if (strip_suffix(start, &end, "_f")) {
|
||||
high_level = MR_TRUE;
|
||||
matched = MR_TRUE;
|
||||
pred_or_func = "function";
|
||||
} else if (strip_suffix(start, &end, "_p")) {
|
||||
high_level = MR_TRUE;
|
||||
matched = MR_TRUE;
|
||||
pred_or_func = "predicate";
|
||||
} else {
|
||||
/*
|
||||
** It's not a function.
|
||||
** But it could be either an LLDS predicate,
|
||||
** or an MLDS compiler-generated predicate.
|
||||
*/
|
||||
high_level = (strstr(start, unify2) ||
|
||||
strstr(start, compare2) ||
|
||||
strstr(start, index2));
|
||||
pred_or_func = "predicate";
|
||||
}
|
||||
|
||||
if (end == start) goto not_plain_mercury;
|
||||
|
||||
/*
|
||||
** scan back past the arity number and then parse it
|
||||
*/
|
||||
|
||||
if (!cut_trailing_underscore_integer(start, &end, &arity)) {
|
||||
goto wrong_format;
|
||||
goto not_plain_mercury;
|
||||
}
|
||||
|
||||
if (high_level) {
|
||||
module = strip_module_name(&start, end,
|
||||
trailing_context_1, trailing_context_1_hl_suffixes);
|
||||
}
|
||||
/*
|
||||
** Now start processing from the start of the string again.
|
||||
** Check whether the start of the string matches the name of
|
||||
@@ -334,16 +371,27 @@ demangle(const char *orig_name)
|
||||
** skip past the prefix.
|
||||
*/
|
||||
|
||||
if (strip_prefix(&start, unify)) {
|
||||
if (strip_prefix(&start, unify1)) {
|
||||
category = UNIFY;
|
||||
} else if (strip_prefix(&start, compare)) {
|
||||
} else if (strip_prefix(&start, compare1)) {
|
||||
category = COMPARE;
|
||||
if (mode_num != 0) goto wrong_format;
|
||||
} else if (strip_prefix(&start, mindex)) {
|
||||
if (mode_num != 0) goto not_plain_mercury;
|
||||
} else if (strip_prefix(&start, index1)) {
|
||||
category = INDEX;
|
||||
if (mode_num != 0) goto wrong_format;
|
||||
if (mode_num != 0) goto not_plain_mercury;
|
||||
} else {
|
||||
category = ORDINARY;
|
||||
/*
|
||||
** For ordinary predicates, we should have matched
|
||||
** against something by now --
|
||||
** either the "mercury__" prefix, for LLDS mangling,
|
||||
** or the "_f" or "_p" suffix, for MLDS mangling.
|
||||
*/
|
||||
if (!matched) goto not_plain_mercury;
|
||||
}
|
||||
|
||||
if (category != ORDINARY && start[0] == '_') {
|
||||
start++;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -417,7 +465,9 @@ demangle(const char *orig_name)
|
||||
}
|
||||
}
|
||||
|
||||
module = strip_module_name(&start, end, trailing_context_1);
|
||||
if (!high_level) {
|
||||
module = strip_module_name(&start, end, trailing_context_1, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
** look for "IntroducedFrom" or "DeforestationIn" or "AccFrom"
|
||||
@@ -607,16 +657,48 @@ demangle(const char *orig_name)
|
||||
*/
|
||||
|
||||
not_plain_mercury:
|
||||
/*
|
||||
** Undo any in-place modifications done while trying to demangle
|
||||
** predicate names.
|
||||
*/
|
||||
strcpy(name, orig_name);
|
||||
start = name;
|
||||
end = name + strlen(name);
|
||||
|
||||
if (!strip_prefix(&start, mercury_data)) {
|
||||
goto wrong_format;
|
||||
/*
|
||||
** skip any leading underscore inserted by the C compiler
|
||||
*/
|
||||
if (*start == '_') {
|
||||
start++;
|
||||
}
|
||||
|
||||
if (strip_prefix(&start, base_typeclass_info)) {
|
||||
goto typeclass_info;
|
||||
if (strip_prefix(&start, mercury_data)) {
|
||||
/* LLDS */
|
||||
high_level = MR_FALSE;
|
||||
if (strip_prefix(&start, underscores_base_typeclass_info)) {
|
||||
goto typeclass_info;
|
||||
}
|
||||
} else {
|
||||
/* MLDS */
|
||||
high_level = MR_TRUE;
|
||||
if (strip_prefix(&start, base_typeclass_info)) {
|
||||
goto typeclass_info;
|
||||
}
|
||||
strip_prefix(&start, mercury);
|
||||
}
|
||||
|
||||
module = strip_module_name(&start, end, trailing_context_2);
|
||||
module = strip_module_name(&start, end, trailing_context_2, NULL);
|
||||
if (high_level) {
|
||||
/*
|
||||
** For MLDS, the module name gets duplicated (XXX why?)
|
||||
** So here we must replace `foo:foo' with just `foo'.
|
||||
*/
|
||||
size_t half_len = strlen(module) / 2;
|
||||
if (strncmp(module, module + half_len + 1, half_len) != 0) {
|
||||
goto wrong_format;
|
||||
}
|
||||
module += half_len + 1;
|
||||
}
|
||||
|
||||
if (strip_prefix(&start, type_ctor_info)) {
|
||||
data_category = INFO;
|
||||
@@ -690,7 +772,7 @@ typeclass_info:
|
||||
** layout:
|
||||
** <module-qualified class name>__arity<arity>__
|
||||
*/
|
||||
class_name = strip_module_name(&start, end, trailing_context_3);
|
||||
class_name = strip_module_name(&start, end, trailing_context_3, NULL);
|
||||
/* XXX fix_mangled_ascii() */
|
||||
if (!(strip_prefix(&start, arity_string)
|
||||
&& strip_leading_integer(&start, &class_arity)
|
||||
@@ -713,7 +795,7 @@ typeclass_info:
|
||||
if (class_arg_num != 0) {
|
||||
strcat(class_arg_buf, ", ");
|
||||
}
|
||||
class_arg = strip_module_name(&start, end, trailing_context_3);
|
||||
class_arg = strip_module_name(&start, end, trailing_context_3, NULL);
|
||||
if (!(strip_prefix(&start, arity_string)
|
||||
&& strip_leading_integer(&start, &arity)
|
||||
&& strip_prefix(&start, "__")))
|
||||
@@ -744,7 +826,8 @@ wrong_format:
|
||||
** left.
|
||||
*/
|
||||
static const char *
|
||||
strip_module_name(char **start_ptr, char *end, const char *trailing_context[])
|
||||
strip_module_name(char **start_ptr, char *end,
|
||||
const char *special_prefixes[], const char *special_suffixes[])
|
||||
{
|
||||
const char *module; /* module name */
|
||||
char *module_end; /* end of the module name */
|
||||
@@ -765,10 +848,18 @@ strip_module_name(char **start_ptr, char *end, const char *trailing_context[])
|
||||
** Check for special cases
|
||||
*/
|
||||
MR_bool stop = MR_FALSE;
|
||||
for (i = 0; trailing_context[i] != NULL; i++) {
|
||||
for (i = 0; special_prefixes[i] != NULL; i++) {
|
||||
if (strncmp(start,
|
||||
trailing_context[i],
|
||||
strlen(trailing_context[i])) == 0)
|
||||
special_prefixes[i],
|
||||
strlen(special_prefixes[i])) == 0)
|
||||
{
|
||||
stop = MR_TRUE;
|
||||
}
|
||||
}
|
||||
for (i = 0; special_suffixes != NULL && special_suffixes[i] != NULL; i++) {
|
||||
if (strncmp(next_double_underscore,
|
||||
special_suffixes[i],
|
||||
strlen(special_suffixes[i])) == 0)
|
||||
{
|
||||
stop = MR_TRUE;
|
||||
}
|
||||
@@ -800,11 +891,10 @@ strip_module_name(char **start_ptr, char *end, const char *trailing_context[])
|
||||
}
|
||||
|
||||
/*
|
||||
** Remove the prefix from a string, if it has
|
||||
** it.
|
||||
** Returns MR_TRUE if it has that prefix, and newstr will
|
||||
** then point to the rest of that string.
|
||||
** If the string doesn't have that prefix, newstr will
|
||||
** Remove the prefix from a string, if it has it.
|
||||
** Returns MR_TRUE if the string has that prefix, and
|
||||
** *str will then point to the rest of that string.
|
||||
** If the string doesn't have that prefix, *str will
|
||||
** be unchanged, and the function will return MR_FALSE.
|
||||
*/
|
||||
static MR_bool
|
||||
@@ -821,6 +911,26 @@ strip_prefix(char **str, const char *prefix)
|
||||
return MR_FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
** Remove the suffix from a string, if it has it.
|
||||
** Returns MR_TRUE if the string between start and *end
|
||||
** has the specified suffix, and sets *end to point to
|
||||
** the beginning of the suffix.
|
||||
*/
|
||||
static MR_bool
|
||||
strip_suffix(const char *start, char **end, const char *suffix)
|
||||
{
|
||||
int len;
|
||||
|
||||
len = strlen(suffix);
|
||||
|
||||
if (*end - start >= len && strncmp(*end - len, suffix, len) == 0) {
|
||||
*end -= len;
|
||||
return MR_TRUE;
|
||||
}
|
||||
return MR_FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
** If the string pointed to by *start_ptr starts with
|
||||
** an integer, then advance *start_ptr past the leading integer,
|
||||
|
||||
Reference in New Issue
Block a user