xref: /netbsd-src/external/gpl3/gdb.old/dist/gdb/gdb-gdb.py.in (revision 6881a4007f077b54e5f51159c52b9b25f57deb0d)
1*6881a400Schristos# Copyright (C) 2009-2023 Free Software Foundation, Inc.
27f2ac410Schristos#
37f2ac410Schristos# This file is part of GDB.
47f2ac410Schristos#
57f2ac410Schristos# This program is free software; you can redistribute it and/or modify
67f2ac410Schristos# it under the terms of the GNU General Public License as published by
77f2ac410Schristos# the Free Software Foundation; either version 3 of the License, or
87f2ac410Schristos# (at your option) any later version.
97f2ac410Schristos#
107f2ac410Schristos# This program is distributed in the hope that it will be useful,
117f2ac410Schristos# but WITHOUT ANY WARRANTY; without even the implied warranty of
127f2ac410Schristos# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
137f2ac410Schristos# GNU General Public License for more details.
147f2ac410Schristos#
157f2ac410Schristos# You should have received a copy of the GNU General Public License
167f2ac410Schristos# along with this program.  If not, see <http://www.gnu.org/licenses/>.
177f2ac410Schristos
187f2ac410Schristosimport gdb
197f2ac410Schristosimport os.path
207f2ac410Schristos
217f2ac410Schristos
227f2ac410Schristosclass TypeFlag:
237f2ac410Schristos    """A class that allows us to store a flag name, its short name,
247f2ac410Schristos    and its value.
257f2ac410Schristos
267f2ac410Schristos    In the GDB sources, struct type has a component called instance_flags
277f2ac410Schristos    in which the value is the addition of various flags.  These flags are
287f2ac410Schristos    defined by the enumerates type_instance_flag_value.  This class helps us
297f2ac410Schristos    recreate a list with all these flags that is easy to manipulate and sort.
307f2ac410Schristos    Because all flag names start with TYPE_INSTANCE_FLAG_, a short_name
317f2ac410Schristos    attribute is provided that strips this prefix.
327f2ac410Schristos
337f2ac410Schristos    ATTRIBUTES
347f2ac410Schristos      name:  The enumeration name (eg: "TYPE_INSTANCE_FLAG_CONST").
357f2ac410Schristos      value: The associated value.
367f2ac410Schristos      short_name: The enumeration name, with the suffix stripped.
377f2ac410Schristos    """
387f2ac410Schristos
397f2ac410Schristos    def __init__(self, name, value):
407f2ac410Schristos        self.name = name
417f2ac410Schristos        self.value = value
42*6881a400Schristos        self.short_name = name.replace("TYPE_INSTANCE_FLAG_", "")
437f2ac410Schristos
447f2ac410Schristos    def __lt__(self, other):
457f2ac410Schristos        """Sort by value order."""
467f2ac410Schristos        return self.value < other.value
477f2ac410Schristos
487f2ac410Schristos
497f2ac410Schristos# A list of all existing TYPE_INSTANCE_FLAGS_* enumerations,
507f2ac410Schristos# stored as TypeFlags objects.  Lazy-initialized.
517f2ac410SchristosTYPE_FLAGS = None
527f2ac410Schristos
537f2ac410Schristos
547f2ac410Schristosclass TypeFlagsPrinter:
557f2ac410Schristos    """A class that prints a decoded form of an instance_flags value.
567f2ac410Schristos
577f2ac410Schristos    This class uses a global named TYPE_FLAGS, which is a list of
587f2ac410Schristos    all defined TypeFlag values.  Using a global allows us to compute
597f2ac410Schristos    this list only once.
607f2ac410Schristos
617f2ac410Schristos    This class relies on a couple of enumeration types being defined.
627f2ac410Schristos    If not, then printing of the instance_flag is going to be degraded,
637f2ac410Schristos    but it's not a fatal error.
647f2ac410Schristos    """
657f2ac410Schristos
667f2ac410Schristos    def __init__(self, val):
677f2ac410Schristos        self.val = val
687f2ac410Schristos
697f2ac410Schristos    def __str__(self):
707f2ac410Schristos        global TYPE_FLAGS
717f2ac410Schristos        if TYPE_FLAGS is None:
727f2ac410Schristos            self.init_TYPE_FLAGS()
737f2ac410Schristos        if not self.val:
747f2ac410Schristos            return "0"
757f2ac410Schristos        if TYPE_FLAGS:
76*6881a400Schristos            flag_list = [
77*6881a400Schristos                flag.short_name for flag in TYPE_FLAGS if self.val & flag.value
78*6881a400Schristos            ]
797f2ac410Schristos        else:
807f2ac410Schristos            flag_list = ["???"]
817f2ac410Schristos        return "0x%x [%s]" % (self.val, "|".join(flag_list))
827f2ac410Schristos
837f2ac410Schristos    def init_TYPE_FLAGS(self):
847f2ac410Schristos        """Initialize the TYPE_FLAGS global as a list of TypeFlag objects.
857f2ac410Schristos        This operation requires the search of a couple of enumeration types.
867f2ac410Schristos        If not found, a warning is printed on stdout, and TYPE_FLAGS is
877f2ac410Schristos        set to the empty list.
887f2ac410Schristos
897f2ac410Schristos        The resulting list is sorted by increasing value, to facilitate
907f2ac410Schristos        printing of the list of flags used in an instance_flags value.
917f2ac410Schristos        """
927f2ac410Schristos        global TYPE_FLAGS
937f2ac410Schristos        TYPE_FLAGS = []
947f2ac410Schristos        try:
957f2ac410Schristos            iflags = gdb.lookup_type("enum type_instance_flag_value")
967f2ac410Schristos        except:
977f2ac410Schristos            print("Warning: Cannot find enum type_instance_flag_value type.")
987f2ac410Schristos            print("         `struct type' pretty-printer will be degraded")
997f2ac410Schristos            return
100*6881a400Schristos        TYPE_FLAGS = [TypeFlag(field.name, field.enumval) for field in iflags.fields()]
1017f2ac410Schristos        TYPE_FLAGS.sort()
1027f2ac410Schristos
1037f2ac410Schristos
1047f2ac410Schristosclass StructTypePrettyPrinter:
1057f2ac410Schristos    """Pretty-print an object of type struct type"""
1067f2ac410Schristos
1077f2ac410Schristos    def __init__(self, val):
1087f2ac410Schristos        self.val = val
1097f2ac410Schristos
1107f2ac410Schristos    def to_string(self):
1117f2ac410Schristos        fields = []
112*6881a400Schristos        fields.append("pointer_type = %s" % self.val["pointer_type"])
113*6881a400Schristos        fields.append("reference_type = %s" % self.val["reference_type"])
114*6881a400Schristos        fields.append("chain = %s" % self.val["reference_type"])
115*6881a400Schristos        fields.append(
116*6881a400Schristos            "instance_flags = %s" % TypeFlagsPrinter(self.val["m_instance_flags"])
117*6881a400Schristos        )
118*6881a400Schristos        fields.append("length = %d" % self.val["m_length"])
119*6881a400Schristos        fields.append("main_type = %s" % self.val["main_type"])
1207f2ac410Schristos        return "\n{" + ",\n ".join(fields) + "}"
1217f2ac410Schristos
1227f2ac410Schristos
1237f2ac410Schristosclass StructMainTypePrettyPrinter:
1247f2ac410Schristos    """Pretty-print an objet of type main_type"""
1257f2ac410Schristos
1267f2ac410Schristos    def __init__(self, val):
1277f2ac410Schristos        self.val = val
1287f2ac410Schristos
1297f2ac410Schristos    def flags_to_string(self):
1307f2ac410Schristos        """struct main_type contains a series of components that
1317f2ac410Schristos        are one-bit ints whose name start with "flag_".  For instance:
1327f2ac410Schristos        flag_unsigned, flag_stub, etc.  In essence, these components are
1337f2ac410Schristos        really boolean flags, and this method prints a short synthetic
1347f2ac410Schristos        version of the value of all these flags.  For instance, if
1357f2ac410Schristos        flag_unsigned and flag_static are the only components set to 1,
1367f2ac410Schristos        this function will return "unsigned|static".
1377f2ac410Schristos        """
138*6881a400Schristos        fields = [
139*6881a400Schristos            field.name.replace("flag_", "")
1407f2ac410Schristos            for field in self.val.type.fields()
141*6881a400Schristos            if field.name.startswith("flag_") and self.val[field.name]
142*6881a400Schristos        ]
1437f2ac410Schristos        return "|".join(fields)
1447f2ac410Schristos
1457f2ac410Schristos    def owner_to_string(self):
146*6881a400Schristos        """Return an image of component "owner"."""
147*6881a400Schristos        if self.val["m_flag_objfile_owned"] != 0:
148*6881a400Schristos            return "%s (objfile)" % self.val["m_owner"]["objfile"]
1497f2ac410Schristos        else:
150*6881a400Schristos            return "%s (gdbarch)" % self.val["m_owner"]["gdbarch"]
1517f2ac410Schristos
1527f2ac410Schristos    def struct_field_location_img(self, field_val):
1537f2ac410Schristos        """Return an image of the loc component inside the given field
1547f2ac410Schristos        gdb.Value.
1557f2ac410Schristos        """
156*6881a400Schristos        loc_val = field_val["m_loc"]
157*6881a400Schristos        loc_kind = str(field_val["m_loc_kind"])
1587f2ac410Schristos        if loc_kind == "FIELD_LOC_KIND_BITPOS":
159*6881a400Schristos            return "bitpos = %d" % loc_val["bitpos"]
1607f2ac410Schristos        elif loc_kind == "FIELD_LOC_KIND_ENUMVAL":
161*6881a400Schristos            return "enumval = %d" % loc_val["enumval"]
1627f2ac410Schristos        elif loc_kind == "FIELD_LOC_KIND_PHYSADDR":
163*6881a400Schristos            return "physaddr = 0x%x" % loc_val["physaddr"]
1647f2ac410Schristos        elif loc_kind == "FIELD_LOC_KIND_PHYSNAME":
165*6881a400Schristos            return "physname = %s" % loc_val["physname"]
1667f2ac410Schristos        elif loc_kind == "FIELD_LOC_KIND_DWARF_BLOCK":
167*6881a400Schristos            return "dwarf_block = %s" % loc_val["dwarf_block"]
1687f2ac410Schristos        else:
169*6881a400Schristos            return "m_loc = ??? (unsupported m_loc_kind value)"
1707f2ac410Schristos
1717f2ac410Schristos    def struct_field_img(self, fieldno):
172*6881a400Schristos        """Return an image of the main_type field number FIELDNO."""
173*6881a400Schristos        f = self.val["flds_bnds"]["fields"][fieldno]
1747f2ac410Schristos        label = "flds_bnds.fields[%d]:" % fieldno
175*6881a400Schristos        if f["artificial"]:
1767f2ac410Schristos            label += " (artificial)"
1777f2ac410Schristos        fields = []
178*6881a400Schristos        fields.append("m_name = %s" % f["m_name"])
179*6881a400Schristos        fields.append("m_type = %s" % f["m_type"])
180*6881a400Schristos        fields.append("m_loc_kind = %s" % f["m_loc_kind"])
181*6881a400Schristos        fields.append("bitsize = %d" % f["bitsize"])
1827f2ac410Schristos        fields.append(self.struct_field_location_img(f))
1837f2ac410Schristos        return label + "\n" + "  {" + ",\n   ".join(fields) + "}"
1847f2ac410Schristos
1857d62b00eSchristos    def bound_img(self, bound_name):
1867d62b00eSchristos        """Return an image of the given main_type's bound."""
187*6881a400Schristos        bounds = self.val["flds_bnds"]["bounds"].dereference()
188*6881a400Schristos        b = bounds[bound_name]
189*6881a400Schristos        bnd_kind = str(b["m_kind"])
190*6881a400Schristos        if bnd_kind == "PROP_CONST":
191*6881a400Schristos            return str(b["m_data"]["const_val"])
192*6881a400Schristos        elif bnd_kind == "PROP_UNDEFINED":
193*6881a400Schristos            return "(undefined)"
1947d62b00eSchristos        else:
1957d62b00eSchristos            info = [bnd_kind]
196*6881a400Schristos            if bound_name == "high" and bounds["flag_upper_bound_is_count"]:
197*6881a400Schristos                info.append("upper_bound_is_count")
198*6881a400Schristos            return "{} ({})".format(str(b["m_data"]["baton"]), ",".join(info))
1997d62b00eSchristos
2007f2ac410Schristos    def bounds_img(self):
201*6881a400Schristos        """Return an image of the main_type bounds."""
202*6881a400Schristos        b = self.val["flds_bnds"]["bounds"].dereference()
203*6881a400Schristos        low = self.bound_img("low")
204*6881a400Schristos        high = self.bound_img("high")
2057d62b00eSchristos
2067d62b00eSchristos        img = "flds_bnds.bounds = {%s, %s}" % (low, high)
207*6881a400Schristos        if b["flag_bound_evaluated"]:
208*6881a400Schristos            img += " [evaluated]"
2097d62b00eSchristos        return img
2107f2ac410Schristos
2117f2ac410Schristos    def type_specific_img(self):
2127f2ac410Schristos        """Return a string image of the main_type type_specific union.
2137f2ac410Schristos        Only the relevant component of that union is printed (based on
2147f2ac410Schristos        the value of the type_specific_kind field.
2157f2ac410Schristos        """
216*6881a400Schristos        type_specific_kind = str(self.val["type_specific_field"])
217*6881a400Schristos        type_specific = self.val["type_specific"]
2187f2ac410Schristos        if type_specific_kind == "TYPE_SPECIFIC_NONE":
219*6881a400Schristos            img = "type_specific_field = %s" % type_specific_kind
2207f2ac410Schristos        elif type_specific_kind == "TYPE_SPECIFIC_CPLUS_STUFF":
221*6881a400Schristos            img = "cplus_stuff = %s" % type_specific["cplus_stuff"]
2227f2ac410Schristos        elif type_specific_kind == "TYPE_SPECIFIC_GNAT_STUFF":
223*6881a400Schristos            img = (
224*6881a400Schristos                "gnat_stuff = {descriptive_type = %s}"
225*6881a400Schristos                % type_specific["gnat_stuff"]["descriptive_type"]
226*6881a400Schristos            )
2277f2ac410Schristos        elif type_specific_kind == "TYPE_SPECIFIC_FLOATFORMAT":
228*6881a400Schristos            img = "floatformat[0..1] = %s" % type_specific["floatformat"]
2297f2ac410Schristos        elif type_specific_kind == "TYPE_SPECIFIC_FUNC":
230*6881a400Schristos            img = (
231*6881a400Schristos                "calling_convention = %d"
232*6881a400Schristos                % type_specific["func_stuff"]["calling_convention"]
233*6881a400Schristos            )
2347f2ac410Schristos            # tail_call_list is not printed.
2357f2ac410Schristos        elif type_specific_kind == "TYPE_SPECIFIC_SELF_TYPE":
236*6881a400Schristos            img = "self_type = %s" % type_specific["self_type"]
237*6881a400Schristos        elif type_specific_kind == "TYPE_SPECIFIC_FIXED_POINT":
238*6881a400Schristos            # The scaling factor is an opaque structure, so we cannot
239*6881a400Schristos            # decode its value from Python (not without insider knowledge).
240*6881a400Schristos            img = (
241*6881a400Schristos                "scaling_factor: <opaque> (call __gmpz_dump with "
242*6881a400Schristos                " _mp_num and _mp_den fields if needed)"
243*6881a400Schristos            )
244*6881a400Schristos        elif type_specific_kind == "TYPE_SPECIFIC_INT":
245*6881a400Schristos            img = "int_stuff = { bit_size = %d, bit_offset = %d }" % (
246*6881a400Schristos                type_specific["int_stuff"]["bit_size"],
247*6881a400Schristos                type_specific["int_stuff"]["bit_offset"],
248*6881a400Schristos            )
2497f2ac410Schristos        else:
250*6881a400Schristos            img = (
251*6881a400Schristos                "type_specific = ??? (unknown type_specific_kind: %s)"
252*6881a400Schristos                % type_specific_kind
253*6881a400Schristos            )
2547f2ac410Schristos        return img
2557f2ac410Schristos
2567f2ac410Schristos    def to_string(self):
257*6881a400Schristos        """Return a pretty-printed image of our main_type."""
2587f2ac410Schristos        fields = []
259*6881a400Schristos        fields.append("name = %s" % self.val["name"])
260*6881a400Schristos        fields.append("code = %s" % self.val["code"])
2617f2ac410Schristos        fields.append("flags = [%s]" % self.flags_to_string())
2627f2ac410Schristos        fields.append("owner = %s" % self.owner_to_string())
263*6881a400Schristos        fields.append("target_type = %s" % self.val["m_target_type"])
264*6881a400Schristos        if self.val["nfields"] > 0:
265*6881a400Schristos            for fieldno in range(self.val["nfields"]):
2667f2ac410Schristos                fields.append(self.struct_field_img(fieldno))
267*6881a400Schristos        if self.val["code"] == gdb.TYPE_CODE_RANGE:
2687f2ac410Schristos            fields.append(self.bounds_img())
2697f2ac410Schristos        fields.append(self.type_specific_img())
2707f2ac410Schristos
2717f2ac410Schristos        return "\n{" + ",\n ".join(fields) + "}"
2727f2ac410Schristos
2737f2ac410Schristos
2747f2ac410Schristosclass CoreAddrPrettyPrinter:
2757f2ac410Schristos    """Print CORE_ADDR values as hex."""
2767f2ac410Schristos
2777f2ac410Schristos    def __init__(self, val):
2787f2ac410Schristos        self._val = val
2797f2ac410Schristos
2807f2ac410Schristos    def to_string(self):
2817f2ac410Schristos        return hex(int(self._val))
2827f2ac410Schristos
2837f2ac410Schristos
284*6881a400Schristosclass IntrusiveListPrinter:
285*6881a400Schristos    """Print a struct intrusive_list."""
286*6881a400Schristos
287*6881a400Schristos    def __init__(self, val):
288*6881a400Schristos        self._val = val
289*6881a400Schristos
290*6881a400Schristos        # Type of linked items.
291*6881a400Schristos        self._item_type = self._val.type.template_argument(0)
292*6881a400Schristos        self._node_ptr_type = gdb.lookup_type(
293*6881a400Schristos            "intrusive_list_node<{}>".format(self._item_type.tag)
294*6881a400Schristos        ).pointer()
295*6881a400Schristos
296*6881a400Schristos        # Type of value -> node converter.
297*6881a400Schristos        self._conv_type = self._val.type.template_argument(1)
298*6881a400Schristos
299*6881a400Schristos        if self._uses_member_node():
300*6881a400Schristos            # The second template argument of intrusive_member_node is a member
301*6881a400Schristos            # pointer value.  Its value is the offset of the node member in the
302*6881a400Schristos            # enclosing type.
303*6881a400Schristos            member_node_ptr = self._conv_type.template_argument(1)
304*6881a400Schristos            member_node_ptr = member_node_ptr.cast(gdb.lookup_type("int"))
305*6881a400Schristos            self._member_node_offset = int(member_node_ptr)
306*6881a400Schristos
307*6881a400Schristos            # This is only needed in _as_node_ptr if using a member node.  Look it
308*6881a400Schristos            # up here so we only do it once.
309*6881a400Schristos            self._char_ptr_type = gdb.lookup_type("char").pointer()
310*6881a400Schristos
311*6881a400Schristos    def display_hint(self):
312*6881a400Schristos        return "array"
313*6881a400Schristos
314*6881a400Schristos    def _uses_member_node(self):
315*6881a400Schristos        """Return True if the list items use a node as a member, False if
316*6881a400Schristos        they use a node as a base class.
317*6881a400Schristos        """
318*6881a400Schristos
319*6881a400Schristos        if self._conv_type.name.startswith("intrusive_member_node<"):
320*6881a400Schristos            return True
321*6881a400Schristos        elif self._conv_type.name.startswith("intrusive_base_node<"):
322*6881a400Schristos            return False
323*6881a400Schristos        else:
324*6881a400Schristos            raise RuntimeError(
325*6881a400Schristos                "Unexpected intrusive_list value -> node converter type: {}".format(
326*6881a400Schristos                    self._conv_type.name
327*6881a400Schristos                )
328*6881a400Schristos            )
329*6881a400Schristos
330*6881a400Schristos    def to_string(self):
331*6881a400Schristos        s = "intrusive list of {}".format(self._item_type)
332*6881a400Schristos
333*6881a400Schristos        if self._uses_member_node():
334*6881a400Schristos            node_member = self._conv_type.template_argument(1)
335*6881a400Schristos            s += ", linked through {}".format(node_member)
336*6881a400Schristos
337*6881a400Schristos        return s
338*6881a400Schristos
339*6881a400Schristos    def _as_node_ptr(self, elem_ptr):
340*6881a400Schristos        """Given ELEM_PTR, a pointer to a list element, return a pointer to the
341*6881a400Schristos        corresponding intrusive_list_node.
342*6881a400Schristos        """
343*6881a400Schristos
344*6881a400Schristos        assert elem_ptr.type.code == gdb.TYPE_CODE_PTR
345*6881a400Schristos
346*6881a400Schristos        if self._uses_member_node():
347*6881a400Schristos            # Node as a member: add the member node offset from to the element's
348*6881a400Schristos            # address to get the member node's address.
349*6881a400Schristos            elem_char_ptr = elem_ptr.cast(self._char_ptr_type)
350*6881a400Schristos            node_char_ptr = elem_char_ptr + self._member_node_offset
351*6881a400Schristos            return node_char_ptr.cast(self._node_ptr_type)
352*6881a400Schristos        else:
353*6881a400Schristos            # Node as a base: just casting from node pointer to item pointer
354*6881a400Schristos            # will adjust the pointer value.
355*6881a400Schristos            return elem_ptr.cast(self._node_ptr_type)
356*6881a400Schristos
357*6881a400Schristos    def _children_generator(self):
358*6881a400Schristos        """Generator that yields one tuple per list item."""
359*6881a400Schristos
360*6881a400Schristos        elem_ptr = self._val["m_front"]
361*6881a400Schristos        idx = 0
362*6881a400Schristos        while elem_ptr != 0:
363*6881a400Schristos            yield (str(idx), elem_ptr.dereference())
364*6881a400Schristos            node_ptr = self._as_node_ptr(elem_ptr)
365*6881a400Schristos            elem_ptr = node_ptr["next"]
366*6881a400Schristos            idx += 1
367*6881a400Schristos
368*6881a400Schristos    def children(self):
369*6881a400Schristos        return self._children_generator()
370*6881a400Schristos
371*6881a400Schristos
3727f2ac410Schristosdef type_lookup_function(val):
3737f2ac410Schristos    """A routine that returns the correct pretty printer for VAL
3747f2ac410Schristos    if appropriate.  Returns None otherwise.
3757f2ac410Schristos    """
376*6881a400Schristos    tag = val.type.tag
377*6881a400Schristos    name = val.type.name
378*6881a400Schristos    if tag == "type":
3797f2ac410Schristos        return StructTypePrettyPrinter(val)
380*6881a400Schristos    elif tag == "main_type":
3817f2ac410Schristos        return StructMainTypePrettyPrinter(val)
382*6881a400Schristos    elif name == "CORE_ADDR":
3837f2ac410Schristos        return CoreAddrPrettyPrinter(val)
384*6881a400Schristos    elif tag is not None and tag.startswith("intrusive_list<"):
385*6881a400Schristos        return IntrusiveListPrinter(val)
3867f2ac410Schristos    return None
3877f2ac410Schristos
3887f2ac410Schristos
3897f2ac410Schristosdef register_pretty_printer(objfile):
390*6881a400Schristos    """A routine to register a pretty-printer against the given OBJFILE."""
3917f2ac410Schristos    objfile.pretty_printers.append(type_lookup_function)
3927f2ac410Schristos
3937f2ac410Schristos
3947f2ac410Schristosif __name__ == "__main__":
3957f2ac410Schristos    if gdb.current_objfile() is not None:
3967f2ac410Schristos        # This is the case where this script is being "auto-loaded"
3977f2ac410Schristos        # for a given objfile.  Register the pretty-printer for that
3987f2ac410Schristos        # objfile.
3997f2ac410Schristos        register_pretty_printer(gdb.current_objfile())
4007f2ac410Schristos    else:
4017f2ac410Schristos        # We need to locate the objfile corresponding to the GDB
4027f2ac410Schristos        # executable, and register the pretty-printer for that objfile.
4037f2ac410Schristos        # FIXME: The condition used to match the objfile is too simplistic
4047f2ac410Schristos        # and will not work on Windows.
4057f2ac410Schristos        for objfile in gdb.objfiles():
4067f2ac410Schristos            if os.path.basename(objfile.filename) == "gdb":
4077f2ac410Schristos                objfile.pretty_printers.append(type_lookup_function)
408