gdb/gdbserver/linux-s390-low.c - gdb

Global variables defined

Functions defined

Macros defined

Source code

  1. /* GNU/Linux S/390 specific low level interface, for the remote server
  2.    for GDB.
  3.    Copyright (C) 2001-2015 Free Software Foundation, Inc.

  4.    This file is part of GDB.

  5.    This program is free software; you can redistribute it and/or modify
  6.    it under the terms of the GNU General Public License as published by
  7.    the Free Software Foundation; either version 3 of the License, or
  8.    (at your option) any later version.

  9.    This program is distributed in the hope that it will be useful,
  10.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.    GNU General Public License for more details.

  13.    You should have received a copy of the GNU General Public License
  14.    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */

  15. /* This file is used for both 31-bit and 64-bit S/390 systems.  */

  16. #include "server.h"
  17. #include "linux-low.h"
  18. #include "elf/common.h"

  19. #include <asm/ptrace.h>
  20. #include <sys/ptrace.h>
  21. #include <sys/uio.h>
  22. #include <elf.h>

  23. #ifndef HWCAP_S390_HIGH_GPRS
  24. #define HWCAP_S390_HIGH_GPRS 512
  25. #endif

  26. #ifndef HWCAP_S390_TE
  27. #define HWCAP_S390_TE 1024
  28. #endif

  29. #ifndef PTRACE_GETREGSET
  30. #define PTRACE_GETREGSET 0x4204
  31. #endif

  32. #ifndef PTRACE_SETREGSET
  33. #define PTRACE_SETREGSET 0x4205
  34. #endif

  35. /* Defined in auto-generated file s390-linux32.c.  */
  36. void init_registers_s390_linux32 (void);
  37. extern const struct target_desc *tdesc_s390_linux32;

  38. /* Defined in auto-generated file s390-linux32v1.c.  */
  39. void init_registers_s390_linux32v1 (void);
  40. extern const struct target_desc *tdesc_s390_linux32v1;

  41. /* Defined in auto-generated file s390-linux32v2.c.  */
  42. void init_registers_s390_linux32v2 (void);
  43. extern const struct target_desc *tdesc_s390_linux32v2;

  44. /* Defined in auto-generated file s390-linux64.c.  */
  45. void init_registers_s390_linux64 (void);
  46. extern const struct target_desc *tdesc_s390_linux64;

  47. /* Defined in auto-generated file s390-linux64v1.c.  */
  48. void init_registers_s390_linux64v1 (void);
  49. extern const struct target_desc *tdesc_s390_linux64v1;

  50. /* Defined in auto-generated file s390-linux64v2.c.  */
  51. void init_registers_s390_linux64v2 (void);
  52. extern const struct target_desc *tdesc_s390_linux64v2;

  53. /* Defined in auto-generated file s390-te-linux64.c.  */
  54. void init_registers_s390_te_linux64 (void);
  55. extern const struct target_desc *tdesc_s390_te_linux64;

  56. /* Defined in auto-generated file s390x-linux64.c.  */
  57. void init_registers_s390x_linux64 (void);
  58. extern const struct target_desc *tdesc_s390x_linux64;

  59. /* Defined in auto-generated file s390x-linux64v1.c.  */
  60. void init_registers_s390x_linux64v1 (void);
  61. extern const struct target_desc *tdesc_s390x_linux64v1;

  62. /* Defined in auto-generated file s390x-linux64v2.c.  */
  63. void init_registers_s390x_linux64v2 (void);
  64. extern const struct target_desc *tdesc_s390x_linux64v2;

  65. /* Defined in auto-generated file s390x-te-linux64.c.  */
  66. void init_registers_s390x_te_linux64 (void);
  67. extern const struct target_desc *tdesc_s390x_te_linux64;

  68. #define s390_num_regs 52

  69. static int s390_regmap[] = {
  70.   PT_PSWMASK, PT_PSWADDR,

  71.   PT_GPR0, PT_GPR1, PT_GPR2, PT_GPR3,
  72.   PT_GPR4, PT_GPR5, PT_GPR6, PT_GPR7,
  73.   PT_GPR8, PT_GPR9, PT_GPR10, PT_GPR11,
  74.   PT_GPR12, PT_GPR13, PT_GPR14, PT_GPR15,

  75.   PT_ACR0, PT_ACR1, PT_ACR2, PT_ACR3,
  76.   PT_ACR4, PT_ACR5, PT_ACR6, PT_ACR7,
  77.   PT_ACR8, PT_ACR9, PT_ACR10, PT_ACR11,
  78.   PT_ACR12, PT_ACR13, PT_ACR14, PT_ACR15,

  79.   PT_FPC,

  80. #ifndef __s390x__
  81.   PT_FPR0_HI, PT_FPR1_HI, PT_FPR2_HI, PT_FPR3_HI,
  82.   PT_FPR4_HI, PT_FPR5_HI, PT_FPR6_HI, PT_FPR7_HI,
  83.   PT_FPR8_HI, PT_FPR9_HI, PT_FPR10_HI, PT_FPR11_HI,
  84.   PT_FPR12_HI, PT_FPR13_HI, PT_FPR14_HI, PT_FPR15_HI,
  85. #else
  86.   PT_FPR0, PT_FPR1, PT_FPR2, PT_FPR3,
  87.   PT_FPR4, PT_FPR5, PT_FPR6, PT_FPR7,
  88.   PT_FPR8, PT_FPR9, PT_FPR10, PT_FPR11,
  89.   PT_FPR12, PT_FPR13, PT_FPR14, PT_FPR15,
  90. #endif

  91.   PT_ORIGGPR2,
  92. };

  93. #ifdef __s390x__
  94. #define s390_num_regs_3264 68

  95. static int s390_regmap_3264[] = {
  96.   PT_PSWMASK, PT_PSWADDR,

  97.   PT_GPR0, PT_GPR0, PT_GPR1, PT_GPR1,
  98.   PT_GPR2, PT_GPR2, PT_GPR3, PT_GPR3,
  99.   PT_GPR4, PT_GPR4, PT_GPR5, PT_GPR5,
  100.   PT_GPR6, PT_GPR6, PT_GPR7, PT_GPR7,
  101.   PT_GPR8, PT_GPR8, PT_GPR9, PT_GPR9,
  102.   PT_GPR10, PT_GPR10, PT_GPR11, PT_GPR11,
  103.   PT_GPR12, PT_GPR12, PT_GPR13, PT_GPR13,
  104.   PT_GPR14, PT_GPR14, PT_GPR15, PT_GPR15,

  105.   PT_ACR0, PT_ACR1, PT_ACR2, PT_ACR3,
  106.   PT_ACR4, PT_ACR5, PT_ACR6, PT_ACR7,
  107.   PT_ACR8, PT_ACR9, PT_ACR10, PT_ACR11,
  108.   PT_ACR12, PT_ACR13, PT_ACR14, PT_ACR15,

  109.   PT_FPC,

  110.   PT_FPR0, PT_FPR1, PT_FPR2, PT_FPR3,
  111.   PT_FPR4, PT_FPR5, PT_FPR6, PT_FPR7,
  112.   PT_FPR8, PT_FPR9, PT_FPR10, PT_FPR11,
  113.   PT_FPR12, PT_FPR13, PT_FPR14, PT_FPR15,

  114.   PT_ORIGGPR2,
  115. };
  116. #endif


  117. static int
  118. s390_cannot_fetch_register (int regno)
  119. {
  120.   return 0;
  121. }

  122. static int
  123. s390_cannot_store_register (int regno)
  124. {
  125.   return 0;
  126. }

  127. static void
  128. s390_collect_ptrace_register (struct regcache *regcache, int regno, char *buf)
  129. {
  130.   int size = register_size (regcache->tdesc, regno);
  131.   if (size < sizeof (long))
  132.     {
  133.       const struct regs_info *regs_info = (*the_low_target.regs_info) ();
  134.       struct usrregs_info *usr = regs_info->usrregs;
  135.       int regaddr = usr->regmap[regno];

  136.       memset (buf, 0, sizeof (long));

  137.       if ((regno ^ 1) < usr->num_regs
  138.           && usr->regmap[regno ^ 1] == regaddr)
  139.         {
  140.           collect_register (regcache, regno & ~1, buf);
  141.           collect_register (regcache, (regno & ~1) + 1,
  142.                             buf + sizeof (long) - size);
  143.         }
  144.       else if (regaddr == PT_PSWMASK)
  145.         {
  146.           /* Convert 4-byte PSW mask to 8 bytes by clearing bit 12 and copying
  147.              the basic addressing mode bit from the PSW address.  */
  148.           char *addr = alloca (register_size (regcache->tdesc, regno ^ 1));
  149.           collect_register (regcache, regno, buf);
  150.           collect_register (regcache, regno ^ 1, addr);
  151.           buf[1] &= ~0x8;
  152.           buf[size] |= (addr[0] & 0x80);
  153.         }
  154.       else if (regaddr == PT_PSWADDR)
  155.         {
  156.           /* Convert 4-byte PSW address to 8 bytes by clearing the addressing
  157.              mode bit (which gets copied to the PSW mask instead).  */
  158.           collect_register (regcache, regno, buf + sizeof (long) - size);
  159.           buf[sizeof (long) - size] &= ~0x80;
  160.         }
  161.       else if ((regaddr >= PT_GPR0 && regaddr <= PT_GPR15)
  162.                || regaddr == PT_ORIGGPR2)
  163.         collect_register (regcache, regno, buf + sizeof (long) - size);
  164.       else
  165.         collect_register (regcache, regno, buf);
  166.     }
  167.   else
  168.     collect_register (regcache, regno, buf);
  169. }

  170. static void
  171. s390_supply_ptrace_register (struct regcache *regcache,
  172.                              int regno, const char *buf)
  173. {
  174.   int size = register_size (regcache->tdesc, regno);
  175.   if (size < sizeof (long))
  176.     {
  177.       const struct regs_info *regs_info = (*the_low_target.regs_info) ();
  178.       struct usrregs_info *usr = regs_info->usrregs;
  179.       int regaddr = usr->regmap[regno];

  180.       if ((regno ^ 1) < usr->num_regs
  181.           && usr->regmap[regno ^ 1] == regaddr)
  182.         {
  183.           supply_register (regcache, regno & ~1, buf);
  184.           supply_register (regcache, (regno & ~1) + 1,
  185.                            buf + sizeof (long) - size);
  186.         }
  187.       else if (regaddr == PT_PSWMASK)
  188.         {
  189.           /* Convert 8-byte PSW mask to 4 bytes by setting bit 12 and copying
  190.              the basic addressing mode into the PSW address.  */
  191.           char *mask = alloca (size);
  192.           char *addr = alloca (register_size (regcache->tdesc, regno ^ 1));
  193.           memcpy (mask, buf, size);
  194.           mask[1] |= 0x8;
  195.           supply_register (regcache, regno, mask);

  196.           collect_register (regcache, regno ^ 1, addr);
  197.           addr[0] &= ~0x80;
  198.           addr[0] |= (buf[size] & 0x80);
  199.           supply_register (regcache, regno ^ 1, addr);
  200.         }
  201.       else if (regaddr == PT_PSWADDR)
  202.         {
  203.           /* Convert 8-byte PSW address to 4 bytes by truncating, but
  204.              keeping the addressing mode bit (which was set from the mask).  */
  205.           char *addr = alloca (size);
  206.           char amode;
  207.           collect_register (regcache, regno, addr);
  208.           amode = addr[0] & 0x80;
  209.           memcpy (addr, buf + sizeof (long) - size, size);
  210.           addr[0] &= ~0x80;
  211.           addr[0] |= amode;
  212.           supply_register (regcache, regno, addr);
  213.         }
  214.       else if ((regaddr >= PT_GPR0 && regaddr <= PT_GPR15)
  215.                || regaddr == PT_ORIGGPR2)
  216.         supply_register (regcache, regno, buf + sizeof (long) - size);
  217.       else
  218.         supply_register (regcache, regno, buf);
  219.     }
  220.   else
  221.     supply_register (regcache, regno, buf);
  222. }

  223. /* Provide only a fill function for the general register setps_lgetregs
  224.    will use this for NPTL support.  */

  225. static void
  226. s390_fill_gregset (struct regcache *regcache, void *buf)
  227. {
  228.   int i;
  229.   const struct regs_info *regs_info = (*the_low_target.regs_info) ();
  230.   struct usrregs_info *usr = regs_info->usrregs;

  231.   for (i = 0; i < usr->num_regs; i++)
  232.     {
  233.       if (usr->regmap[i] < PT_PSWMASK
  234.           || usr->regmap[i] > PT_ACR15)
  235.         continue;

  236.       s390_collect_ptrace_register (regcache, i,
  237.                                     (char *) buf + usr->regmap[i]);
  238.     }
  239. }

  240. /* Fill and store functions for extended register sets.  */

  241. static void
  242. s390_store_last_break (struct regcache *regcache, const void *buf)
  243. {
  244.   const char *p;

  245.   p = (const char *) buf + 8 - register_size (regcache->tdesc, 0);
  246.   supply_register_by_name (regcache, "last_break", p);
  247. }

  248. static void
  249. s390_fill_system_call (struct regcache *regcache, void *buf)
  250. {
  251.   collect_register_by_name (regcache, "system_call", buf);
  252. }

  253. static void
  254. s390_store_system_call (struct regcache *regcache, const void *buf)
  255. {
  256.   supply_register_by_name (regcache, "system_call", buf);
  257. }

  258. static void
  259. s390_store_tdb (struct regcache *regcache, const void *buf)
  260. {
  261.   int tdb0 = find_regno (regcache->tdesc, "tdb0");
  262.   int tr0 = find_regno (regcache->tdesc, "tr0");
  263.   int i;

  264.   for (i = 0; i < 4; i++)
  265.     supply_register (regcache, tdb0 + i, (const char *) buf + 8 * i);

  266.   for (i = 0; i < 16; i++)
  267.     supply_register (regcache, tr0 + i, (const char *) buf + 8 * (16 + i));
  268. }

  269. static struct regset_info s390_regsets[] = {
  270.   { 0, 0, 0, 0, GENERAL_REGS, s390_fill_gregset, NULL },
  271.   /* Last break address is read-only; no fill function.  */
  272.   { PTRACE_GETREGSET, -1, NT_S390_LAST_BREAK, 0, EXTENDED_REGS,
  273.     NULL, s390_store_last_break },
  274.   { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_S390_SYSTEM_CALL, 0,
  275.     EXTENDED_REGS, s390_fill_system_call, s390_store_system_call },
  276.   /* TDB is read-only.  */
  277.   { PTRACE_GETREGSET, -1, NT_S390_TDB, 0, EXTENDED_REGS,
  278.     NULL, s390_store_tdb },
  279.   { 0, 0, 0, -1, -1, NULL, NULL }
  280. };


  281. static const unsigned char s390_breakpoint[] = { 0, 1 };
  282. #define s390_breakpoint_len 2

  283. static CORE_ADDR
  284. s390_get_pc (struct regcache *regcache)
  285. {
  286.   if (register_size (regcache->tdesc, 0) == 4)
  287.     {
  288.       unsigned int pswa;
  289.       collect_register_by_name (regcache, "pswa", &pswa);
  290.       return pswa & 0x7fffffff;
  291.     }
  292.   else
  293.     {
  294.       unsigned long pc;
  295.       collect_register_by_name (regcache, "pswa", &pc);
  296.       return pc;
  297.     }
  298. }

  299. static void
  300. s390_set_pc (struct regcache *regcache, CORE_ADDR newpc)
  301. {
  302.   if (register_size (regcache->tdesc, 0) == 4)
  303.     {
  304.       unsigned int pswa;
  305.       collect_register_by_name (regcache, "pswa", &pswa);
  306.       pswa = (pswa & 0x80000000) | (newpc & 0x7fffffff);
  307.       supply_register_by_name (regcache, "pswa", &pswa);
  308.     }
  309.   else
  310.     {
  311.       unsigned long pc = newpc;
  312.       supply_register_by_name (regcache, "pswa", &pc);
  313.     }
  314. }

  315. #ifdef __s390x__
  316. static unsigned long
  317. s390_get_hwcap (const struct target_desc *tdesc)
  318. {
  319.   int wordsize = register_size (tdesc, 0);
  320.   unsigned char *data = alloca (2 * wordsize);
  321.   int offset = 0;

  322.   while ((*the_target->read_auxv) (offset, data, 2 * wordsize) == 2 * wordsize)
  323.     {
  324.       if (wordsize == 4)
  325.         {
  326.           unsigned int *data_p = (unsigned int *)data;
  327.           if (data_p[0] == AT_HWCAP)
  328.             return data_p[1];
  329.         }
  330.       else
  331.         {
  332.           unsigned long *data_p = (unsigned long *)data;
  333.           if (data_p[0] == AT_HWCAP)
  334.             return data_p[1];
  335.         }

  336.       offset += 2 * wordsize;
  337.     }

  338.   return 0;
  339. }
  340. #endif

  341. static int
  342. s390_check_regset (int pid, int regset, int regsize)
  343. {
  344.   gdb_byte *buf = alloca (regsize);
  345.   struct iovec iov;

  346.   iov.iov_base = buf;
  347.   iov.iov_len = regsize;

  348.   if (ptrace (PTRACE_GETREGSET, pid, (long) regset, (long) &iov) >= 0
  349.       || errno == ENODATA)
  350.     return 1;
  351.   return 0;
  352. }

  353. #ifdef __s390x__
  354. /* For a 31-bit inferior, whether the kernel supports using the full
  355.    64-bit GPRs.  */
  356. static int have_hwcap_s390_high_gprs = 0;
  357. #endif

  358. static void
  359. s390_arch_setup (void)
  360. {
  361.   const struct target_desc *tdesc;
  362.   struct regset_info *regset;

  363.   /* Check whether the kernel supports extra register sets.  */
  364.   int pid = pid_of (current_thread);
  365.   int have_regset_last_break
  366.     = s390_check_regset (pid, NT_S390_LAST_BREAK, 8);
  367.   int have_regset_system_call
  368.     = s390_check_regset (pid, NT_S390_SYSTEM_CALL, 4);
  369.   int have_regset_tdb = s390_check_regset (pid, NT_S390_TDB, 256);

  370.   /* Assume 31-bit inferior process.  */
  371.   if (have_regset_system_call)
  372.     tdesc = tdesc_s390_linux32v2;
  373.   else if (have_regset_last_break)
  374.     tdesc = tdesc_s390_linux32v1;
  375.   else
  376.     tdesc = tdesc_s390_linux32;

  377.   /* On a 64-bit host, check the low bit of the (31-bit) PSWM
  378.      -- if this is one, we actually have a 64-bit inferior.  */
  379. #ifdef __s390x__
  380.   {
  381.     unsigned int pswm;
  382.     struct regcache *regcache = new_register_cache (tdesc);

  383.     fetch_inferior_registers (regcache, find_regno (tdesc, "pswm"));
  384.     collect_register_by_name (regcache, "pswm", &pswm);
  385.     free_register_cache (regcache);

  386.     if (pswm & 1)
  387.       {
  388.         if (have_regset_tdb)
  389.           have_regset_tdb =
  390.             (s390_get_hwcap (tdesc_s390x_linux64v2) & HWCAP_S390_TE) != 0;

  391.         if (have_regset_tdb)
  392.           tdesc = tdesc_s390x_te_linux64;
  393.         else if (have_regset_system_call)
  394.           tdesc = tdesc_s390x_linux64v2;
  395.         else if (have_regset_last_break)
  396.           tdesc = tdesc_s390x_linux64v1;
  397.         else
  398.           tdesc = tdesc_s390x_linux64;
  399.       }

  400.     /* For a 31-bit inferior, check whether the kernel supports
  401.        using the full 64-bit GPRs.  */
  402.     else if (s390_get_hwcap (tdesc) & HWCAP_S390_HIGH_GPRS)
  403.       {
  404.         have_hwcap_s390_high_gprs = 1;
  405.         if (have_regset_tdb)
  406.           have_regset_tdb = (s390_get_hwcap (tdesc) & HWCAP_S390_TE) != 0;

  407.         if (have_regset_tdb)
  408.           tdesc = tdesc_s390_te_linux64;
  409.         else if (have_regset_system_call)
  410.           tdesc = tdesc_s390_linux64v2;
  411.         else if (have_regset_last_break)
  412.           tdesc = tdesc_s390_linux64v1;
  413.         else
  414.           tdesc = tdesc_s390_linux64;
  415.       }
  416.   }
  417. #endif

  418.   /* Update target_regsets according to available register sets.  */
  419.   for (regset = s390_regsets; regset->size >= 0; regset++)
  420.     if (regset->get_request == PTRACE_GETREGSET)
  421.       switch (regset->nt_type)
  422.         {
  423.         case NT_S390_LAST_BREAK:
  424.           regset->size = have_regset_last_break? 8 : 0;
  425.           break;
  426.         case NT_S390_SYSTEM_CALL:
  427.           regset->size = have_regset_system_call? 4 : 0;
  428.           break;
  429.         case NT_S390_TDB:
  430.           regset->size = have_regset_tdb ? 256 : 0;
  431.         default:
  432.           break;
  433.         }

  434.   current_process ()->tdesc = tdesc;
  435. }


  436. static int
  437. s390_breakpoint_at (CORE_ADDR pc)
  438. {
  439.   unsigned char c[s390_breakpoint_len];
  440.   read_inferior_memory (pc, c, s390_breakpoint_len);
  441.   return memcmp (c, s390_breakpoint, s390_breakpoint_len) == 0;
  442. }

  443. static struct usrregs_info s390_usrregs_info =
  444.   {
  445.     s390_num_regs,
  446.     s390_regmap,
  447.   };

  448. static struct regsets_info s390_regsets_info =
  449.   {
  450.     s390_regsets, /* regsets */
  451.     0, /* num_regsets */
  452.     NULL, /* disabled_regsets */
  453.   };

  454. static struct regs_info regs_info =
  455.   {
  456.     NULL, /* regset_bitmap */
  457.     &s390_usrregs_info,
  458.     &s390_regsets_info
  459.   };

  460. #ifdef __s390x__
  461. static struct usrregs_info s390_usrregs_info_3264 =
  462.   {
  463.     s390_num_regs_3264,
  464.     s390_regmap_3264
  465.   };

  466. static struct regsets_info s390_regsets_info_3264 =
  467.   {
  468.     s390_regsets, /* regsets */
  469.     0, /* num_regsets */
  470.     NULL, /* disabled_regsets */
  471.   };

  472. static struct regs_info regs_info_3264 =
  473.   {
  474.     NULL, /* regset_bitmap */
  475.     &s390_usrregs_info_3264,
  476.     &s390_regsets_info_3264
  477.   };
  478. #endif

  479. static const struct regs_info *
  480. s390_regs_info (void)
  481. {
  482. #ifdef __s390x__
  483.   if (have_hwcap_s390_high_gprs)
  484.     {
  485.       const struct target_desc *tdesc = current_process ()->tdesc;

  486.       if (register_size (tdesc, 0) == 4)
  487.         return &regs_info_3264;
  488.     }
  489. #endif
  490.   return &regs_info;
  491. }

  492. struct linux_target_ops the_low_target = {
  493.   s390_arch_setup,
  494.   s390_regs_info,
  495.   s390_cannot_fetch_register,
  496.   s390_cannot_store_register,
  497.   NULL, /* fetch_register */
  498.   s390_get_pc,
  499.   s390_set_pc,
  500.   s390_breakpoint,
  501.   s390_breakpoint_len,
  502.   NULL,
  503.   s390_breakpoint_len,
  504.   s390_breakpoint_at,
  505.   NULL/* supports_z_point_type */
  506.   NULL,
  507.   NULL,
  508.   NULL,
  509.   NULL,
  510.   s390_collect_ptrace_register,
  511.   s390_supply_ptrace_register,
  512. };

  513. void
  514. initialize_low_arch (void)
  515. {
  516.   /* Initialize the Linux target descriptions.  */

  517.   init_registers_s390_linux32 ();
  518.   init_registers_s390_linux32v1 ();
  519.   init_registers_s390_linux32v2 ();
  520.   init_registers_s390_linux64 ();
  521.   init_registers_s390_linux64v1 ();
  522.   init_registers_s390_linux64v2 ();
  523.   init_registers_s390_te_linux64 ();
  524.   init_registers_s390x_linux64 ();
  525.   init_registers_s390x_linux64v1 ();
  526.   init_registers_s390x_linux64v2 ();
  527.   init_registers_s390x_te_linux64 ();

  528.   initialize_regsets_info (&s390_regsets_info);
  529. #ifdef __s390x__
  530.   initialize_regsets_info (&s390_regsets_info_3264);
  531. #endif
  532. }