From patchwork Wed Aug 17 11:46:38 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yury Norov X-Patchwork-Id: 14693 Received: (qmail 112467 invoked by alias); 17 Aug 2016 11:49:09 -0000 Mailing-List: contact libc-alpha-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: libc-alpha-owner@sourceware.org Delivered-To: mailing list libc-alpha@sourceware.org Received: (qmail 112397 invoked by uid 89); 17 Aug 2016 11:49:08 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-1.7 required=5.0 tests=AWL, BAYES_00, KAM_MANYTO, RCVD_IN_DNSWL_NONE, SPF_HELO_PASS autolearn=no version=3.3.2 spammy=King, H*r:sk:mail-sn, 1, 33, 128bit X-HELO: NAM02-SN1-obe.outbound.protection.outlook.com Authentication-Results: spf=none (sender IP is ) smtp.mailfrom=Yuri.Norov@caviumnetworks.com; From: Yury Norov To: , , , , , , CC: , , , , , , , , , , , , , , , , , , , , , Subject: [PATCH 13/18] arm64: signal: share lp64 signal routines to ilp32 Date: Wed, 17 Aug 2016 14:46:38 +0300 Message-ID: <1471434403-25291-14-git-send-email-ynorov@caviumnetworks.com> In-Reply-To: <1471434403-25291-1-git-send-email-ynorov@caviumnetworks.com> References: <1471434403-25291-1-git-send-email-ynorov@caviumnetworks.com> MIME-Version: 1.0 X-ClientProxiedBy: AM3PR03CA045.eurprd03.prod.outlook.com (10.141.191.173) To BN4PR07MB2241.namprd07.prod.outlook.com (10.164.63.147) X-MS-Office365-Filtering-Correlation-Id: b257fa54-ef6c-430b-3956-08d3c6947755 X-Microsoft-Exchange-Diagnostics: 1; BN4PR07MB2241; 2:iwcY+FS+TIdEJbvbuLb46tYrIt/NTC6BTfbdov4qZZjVhwfD8SP4VcCINTgGALERfZrl4lqG8hp8d1D0O9DyhchTZ3wQY7j3FH8BX2qdFDZBSQXgsjCrkweUnSyZrydDl4XKkrQDSB0xytOJ8qPwp79c236by9fRRpzGMeuRBHGIRVbcxyJebmg7cchpMRdg; 3:nI8TobtSB87nbFzByJHaxU7P0/0wkcKTujaleOabX3lwmIVQTsmacFr24+iUo9zZPOxW1KEDhH7s4lZ5NOH66fzkR1bVPjcg5t94ikQWQ9vJpYX3r44QfPXtDjJaTV6W X-Microsoft-Antispam: UriScan:;BCL:0;PCL:0;RULEID:;SRVR:BN4PR07MB2241; X-Microsoft-Exchange-Diagnostics: 1; BN4PR07MB2241; 25:S6p8bCdkcyZIvmbzRGaEZ69/6Bz52A4F9k1hMb0cWjrX8tjN19VRwkGN1sB9pARAurpquarlT3P9/alXWdHJPxJVje6m1d4LqCQYDKxiEUA/xdKmoJoSxNGkUOErqnznlwq+JrloxdIJd39QoWZpnHhhIAb+hZehN29PtbA3sur7nKIKt0hN4ZH4qzRHvhsWqntgRXBSBeh2GYo9wxepcgzMQaruOJ157GAtoF34+cvP881kxpvdE5gr7iHVWUysN+5nRoYHove6yaPqOgGyGCmj+pAlmVw+6KuVIz7ApxpjnbkmPnPNIOEaONwnSgaB/RkiZoXhN+KOr2bwCS0FikslRF9SR9MRIi3oba3NUeGup6dZwcpRPKbYTmaPE7w+e/ij4SMLN0i0zBmTI7OwUP1w7gOou4ViIV6AUo1mjOnxFu/R/9jYY4QLRlGKCuwfKO4sPLzyjtTK5Hs8RFMz6mV2X74kYjeQYqXsuvzf3v1ek6PcovFaCuUKk9gXBxH1Jjafoaw8ZulspufgVzYGicAFw748/hzoPisNunkA1jthcXiFbGYhJjRMpO07wHbrEFufPHyJsvUJ1dP3gsCGkDZJXzAaJayq9zp2wralmvbyubWutAdAsvFKDEyUclqubU/OlGV0FAGOhoi2QH6q36Zbcb+mnbZ2VmPzSWXQQh/D7ocEuJwxSMk1hux5VkOEHR5XHq5oDqO9xt4W9RpXrZi+9LOkPqUb5WkjWI/NO+aByVvRCEaVSxvYnENOPDvdNZO3iFOUZ8vyuV97kCg5ExtltEvjH95rJK+bL3TQ2vGwRtiAUgI4dRTseeht8I+mHvhZYFquguMqtNQRhDIMEXaz4QVYl3UnmGNm6dAOVffX5xSgXqC0S0Dg9Gwz9HkN X-Microsoft-Exchange-Diagnostics: 1; BN4PR07MB2241; 31:18K+Cvjf/PVCJ126FpKPQFE5kR4QA4K4EeArtyYU2cUzRCsDWoLe31+AKd25wxCu1WuQjqhHni+kQNS4M8Ul7qnFRORDql+34HM/PRWIniyjb2/1twp+j71FHjL8JWp7+cbBN3mQSXPnVU7VjaezG80R9gL37kJs00vhIUOuFliWZqrRQ8Gt6p7BkuW3M/A+QQtgxgT25HEazBwuIQ/2ba4pIR77ldfX8s48ed4tXB8=; 20:rpjY994k1mkWMJJSD2zqNt/g5nMViXJ/NEPffWSxORWF5cMcyWYsMKzbQ0nPpEXANpcXdHobE4aY+P+dK5/bRgqcoy/NER1sPZByrKIlcqKKMlmQEBBnFbIl+eiSTldF5j0VGiI8ru1JMLi+wblJ3IZ3f/EVk3R5JjLZsKolcd2UaiwfCLuKNSDVpUA+uGWcM/IIZwwLuG+1Ygl7hYReCKKzZSoZxgACh4ztNguKVgAK5n2f3/Y5TsCNwV+dut3maUiz9X1hxMLhFeyFCP+MQyGetJDvm9oKdRUHfuzpp+bkt4ys+9xGPqB4Upwp90DVUrNadMDAqiELW3/RvhzmPttE8URjBTpjk9ln+WaXaXTjEDtH2nQKK/84R2cXVM4hh58W3DzHINdCF73g2JvydxFAQlHjWuI9qk4phX1Snj4ypts89lVXAz99B6Ipw+VdYePge0qb4xc4I4cPLsE7mvI1XelNH8TzM4QxxwHp5UqNRal1bRTQ1ZOO5e+IQ9mqMg8E2lhbYhsIiMr3r5LaBPiJiFPPOVYlFa89fINkh99oiiBosKK9B7iH/dGDFIkQV/GYhyj98FjP5hzgmkkcqN3Hfy+EUW4JveeJcyagkDg= X-Microsoft-Antispam-PRVS: X-Exchange-Antispam-Report-Test: UriScan:(250305191791016)(22074186197030); X-Exchange-Antispam-Report-CFA-Test: BCL:0; PCL:0; RULEID:(6040176)(601004)(2401047)(8121501046)(5005006)(3002001)(10201501046); SRVR:BN4PR07MB2241; BCL:0; PCL:0; RULEID:; SRVR:BN4PR07MB2241; X-Microsoft-Exchange-Diagnostics: 1; BN4PR07MB2241; 4:GqgEauopNGq9D9u7sMKhAsfDb5kFGg55Vebubwqd8XtvRWNnEFfOplI64AX4JB2bExO5e/qA4DYCEiPp+KZM7x9EQrbNUztFzuG6IQMrqmFwscN2bR6wnt/YdtWk8KUyuM9ICHJFjNwsW/ptep5+dcBwO86NmUrcI6GB6+YmFMmar5enQ4IUjk3sG6sD07jgmru2Pt2XEiKu6cCrvEyH1dG04ztGxxxtU1GBpC6qmgK8HhwiVQumsrRWBqy+CAvkQSS6F48HgXsBJRG4WCkP2U5l/JVgBFGz+sxwmP0CihD4cHmrlR0h0KDxACZbSp+DI6bdAvI+EYT9u7hk+GmAR7Om6j14xusvbHXulPQ+hjvLyz/zN2Ruuff+gF/dUIYYvDinGpXrZ4au9k7S7q2q2O4ITICvxHyAy1mirVs985xEXcMbO6m4qchZyj7A7XwGcrXVxX7FihVpjED5dBQ8cQ== X-Forefront-PRVS: 0037FD6480 X-Forefront-Antispam-Report: SFV:NSPM; SFS:(10009020)(4630300001)(6009001)(6069001)(7916002)(199003)(189002)(2950100001)(68736007)(97736004)(76506005)(4326007)(5001770100001)(2906002)(7846002)(7736002)(92566002)(189998001)(19580405001)(7416002)(3846002)(36756003)(15975445007)(50466002)(77096005)(42186005)(101416001)(50226002)(66066001)(106356001)(229853001)(305945005)(19580395003)(48376002)(586003)(81166006)(33646002)(81156014)(2201001)(47776003)(8676002)(76176999)(5003940100001)(6116002)(105586002)(50986999)(2004002)(2101003); DIR:OUT; SFP:1101; SCL:1; SRVR:BN4PR07MB2241; H:localhost; FPR:; SPF:None; PTR:InfoNoRecords; A:1; MX:1; LANG:en; Received-SPF: None (protection.outlook.com: caviumnetworks.com does not designate permitted sender hosts) X-Microsoft-Exchange-Diagnostics: =?us-ascii?Q?1; BN4PR07MB2241; 23:EQnqgb0YkF4dN4e1Mj1sY3SAG1pNuoR2X8BqRcKBa?= =?us-ascii?Q?XXkEuhKcyK+MTIcgdY/SQX9KCTKF55+FXLI2BJ3V/jsIktHLLimxc6v+Annb?= =?us-ascii?Q?mv3/0IgYFqYJ+yoszJYUaySKxA2s1c84CDRdnIG9Zqtv5uBkqsMZuuhW0ln9?= =?us-ascii?Q?MC9xoKq0mrkDLGV/8edmZalcrWf7XB2ltnJD0/H+XD4eSXxIDNEdoZKdrZ4J?= =?us-ascii?Q?6tAxZ7G+USFgpOvaYG1HlKotDPdQSUvSueOy+teOrNF+fY/CvuaxQGsl3kZr?= =?us-ascii?Q?LFHr+iqAeTMdul8EGJFmeLpDGnZkfbfXPIhULezgnxk1Ryj7f7qMQHc+KA5F?= =?us-ascii?Q?l5noIs8MD7Vt0Aje4F75qkBsimqEkxXpfmFHTlf19ZIdq9L4UrfCY9lRZi0j?= =?us-ascii?Q?2LF/mXTVbdvsMsfRDYwDIOLUYx5Jp7mi1ZWGKlmah21ik7Sd3nV6kSBFQKrL?= =?us-ascii?Q?ArH1H7zI8J/CWjg9rT83IQPVfRwv66/tZfYEbUlkaNPAYwRUOULJew0nZfHc?= =?us-ascii?Q?sXztvOXkDv3yvlvbc0AwKhEnmY3rwxu1EAWfHMfHYKQ5gxHGb5+NcmKH//qK?= =?us-ascii?Q?dtcpfgnnk5jOfaR4FMW7PtoF9PIqAAdx/8FAF5yBU8XFEYcCv4ZrMVZJqgcV?= =?us-ascii?Q?2ZgZF0u7Ay9n/rnOlj4hzpmA3x9d92KOBLqlEa4TcgD5vS21zOhljny17/N+?= =?us-ascii?Q?iEVXUdYfuFnbBiD+nnJ6yaCtENky7GAFnQzXlBpcf53039KUM0xGKMlavWVr?= =?us-ascii?Q?RrA6ccr/ApYnEMLFEDc3EJihvHaHvXUb5w29DV95pnY8BqL8X17+t1sakc2p?= =?us-ascii?Q?zq8sHJJmII8B7Czfe0Tl50YznAe0mLuX12GaaHWi+kBhUldD4rFfqYVbGu+C?= =?us-ascii?Q?PONOh6Pvp6yMAiSKgLqs7iCxe0MI7qp1gR1bro6n7EeTjzmSwJ0aeSVnS7nj?= =?us-ascii?Q?fuimcjXOE6aoRjnWXoWd19uvdCgkC9NoRCxHUKBXbpSw3HkT1WzY0K53AFxb?= =?us-ascii?Q?1SNsFsTkx8EYKHfRQhl1xJZjrV0/T2YbtMmoggmXQ5PENVMKj1G0xkKBDjf/?= =?us-ascii?Q?34a77g1i6fZXC8E9B6M24t5fLVp/dogzUCQGdjaBGcBI1jPAM1xC7WAYvIQW?= =?us-ascii?Q?IwQkH3gbxlAdwN7FjS3WbDXP/Yf9BM8VACESObjRWa9BVdWF/5TieuXu/xA6?= =?us-ascii?Q?26S+SLyop69c5Q=3D?= X-Microsoft-Exchange-Diagnostics: 1; BN4PR07MB2241; 6:Tcj6v5oF6LmTBSE2ouL/xQnJjvMnJUD0iTeXMI+yjzuNxW7/+1D+7eWAuZCnj9REwnTHHdFqXIbeJMOh1ud9dz7O49tjKLeKG5eRe7HHBT0LCYC2hQVibqNgUF5XJ+OHN+H1kMxJ/7wLOQBiot6y5JpjYrqe6juuzruxwrZc9/3t2kopaKqcZLzhn9lCs3v7ju1EMuaz5NHxB1mZL+wl0uT0VfW6Y0i40wnQk90W++CA2cFuQLsXuYRL96sblhjs0WLNlyKaNu2Nb7lTzciAvRUSqsIL3Ox2jwSt685na84=; 5:pXAus/mohXeI8Kg0wDzJgf+dzWcW+IexuqKLbV6MWmqsEO6HJwAyvvfEKDrJXya2Q+nNOk3JUGGE//5lyuzNVXoaCSGRtB8QvtD/80WGSDZLMQY/PMMjo4Dfyc4Q7dSxdYlun/yVVkLt+XecTb4UHQ==; 24:3YSA5fEL+WiZfTK6Wk9v9Zz4BYyTqmD4QWbWHnX+fSpmFOxlmXN2D2EVMNiT1hFULv9+pY0Msozr3P7p0jyxtJR+rBpXbUnxagL0wyytQTE=; 7:FKC78GchxW+KXBA6I7YHw/LlbpSX8Pw/zPCLDsbUFaaUnajyOB8nnMZVvD4gg7+FVNBr5FvwNIUV7HrcwutYs14fhrhIDn22rz6r3Snr3KtoCd1HuqSgHiAPePLrjAxniruGyqTWITmI72zhwewQLqEieb5anKW1K90s5RPl6qhAy2+TNKCdkikTyP0ta+G/0tx/kzTy2bcV7U8HLONo3bH6NRlopFKp49ijuhWaDhyc1AG5YNR18+vIxoNsVPx8 SpamDiagnosticOutput: 1:99 SpamDiagnosticMetadata: NSPM X-OriginatorOrg: caviumnetworks.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 17 Aug 2016 11:48:54.6092 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-Transport-CrossTenantHeadersStamped: BN4PR07MB2241 After that, it will be possible to reuse it in ilp32. Signed-off-by: Yury Norov --- arch/arm64/include/asm/signal_common.h | 33 ++++++++++++ arch/arm64/kernel/signal.c | 93 +++++++++++++++++++++------------- 2 files changed, 92 insertions(+), 34 deletions(-) create mode 100644 arch/arm64/include/asm/signal_common.h diff --git a/arch/arm64/include/asm/signal_common.h b/arch/arm64/include/asm/signal_common.h new file mode 100644 index 0000000..756ed2c --- /dev/null +++ b/arch/arm64/include/asm/signal_common.h @@ -0,0 +1,33 @@ +/* + * Copyright (C) 1995-2009 Russell King + * Copyright (C) 2012 ARM Ltd. + * Copyright (C) 2016 Cavium Networks. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef __ASM_SIGNAL_COMMON_H +#define __ASM_SIGNAL_COMMON_H + +#include +#include +#include + +int preserve_fpsimd_context(struct fpsimd_context __user *ctx); +int restore_fpsimd_context(struct fpsimd_context __user *ctx); +int setup_sigcontext(struct sigcontext __user *uc_mcontext, struct pt_regs *regs); +int restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sf); +void setup_return(struct pt_regs *regs, struct k_sigaction *ka, + void __user *frame, off_t sigframe_off, int usig); + +#endif /* __ASM_SIGNAL_COMMON_H */ diff --git a/arch/arm64/kernel/signal.c b/arch/arm64/kernel/signal.c index be02f65..5c73864 100644 --- a/arch/arm64/kernel/signal.c +++ b/arch/arm64/kernel/signal.c @@ -34,18 +34,26 @@ #include #include #include +#include + +#define RT_SIGFRAME_FP_POS (offsetof(struct rt_sigframe, sig) \ + + offsetof(struct sigframe, fp)) + +struct sigframe { + struct ucontext uc; + u64 fp; + u64 lr; +}; /* * Do a signal return; undo the signal stack. These are aligned to 128-bit. */ struct rt_sigframe { struct siginfo info; - struct ucontext uc; - u64 fp; - u64 lr; + struct sigframe sig; }; -static int preserve_fpsimd_context(struct fpsimd_context __user *ctx) +int preserve_fpsimd_context(struct fpsimd_context __user *ctx) { struct fpsimd_state *fpsimd = ¤t->thread.fpsimd_state; int err; @@ -65,7 +73,7 @@ static int preserve_fpsimd_context(struct fpsimd_context __user *ctx) return err ? -EFAULT : 0; } -static int restore_fpsimd_context(struct fpsimd_context __user *ctx) +int restore_fpsimd_context(struct fpsimd_context __user *ctx) { struct fpsimd_state fpsimd; __u32 magic, size; @@ -93,22 +101,30 @@ static int restore_fpsimd_context(struct fpsimd_context __user *ctx) } static int restore_sigframe(struct pt_regs *regs, - struct rt_sigframe __user *sf) + struct sigframe __user *sf) { sigset_t set; - int i, err; - void *aux = sf->uc.uc_mcontext.__reserved; - + int err; err = __copy_from_user(&set, &sf->uc.uc_sigmask, sizeof(set)); if (err == 0) set_current_blocked(&set); + err |= restore_sigcontext(regs, &sf->uc.uc_mcontext); + return err; +} + + +int restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *uc_mcontext) +{ + int i, err = 0; + void *aux = uc_mcontext->__reserved; + for (i = 0; i < 31; i++) - __get_user_error(regs->regs[i], &sf->uc.uc_mcontext.regs[i], + __get_user_error(regs->regs[i], &uc_mcontext->regs[i], err); - __get_user_error(regs->sp, &sf->uc.uc_mcontext.sp, err); - __get_user_error(regs->pc, &sf->uc.uc_mcontext.pc, err); - __get_user_error(regs->pstate, &sf->uc.uc_mcontext.pstate, err); + __get_user_error(regs->sp, &uc_mcontext->sp, err); + __get_user_error(regs->pc, &uc_mcontext->pc, err); + __get_user_error(regs->pstate, &uc_mcontext->pstate, err); /* * Avoid sys_rt_sigreturn() restarting. @@ -145,10 +161,10 @@ asmlinkage long sys_rt_sigreturn(struct pt_regs *regs) if (!access_ok(VERIFY_READ, frame, sizeof (*frame))) goto badframe; - if (restore_sigframe(regs, frame)) + if (restore_sigframe(regs, &frame->sig)) goto badframe; - if (restore_altstack(&frame->uc.uc_stack)) + if (restore_altstack(&frame->sig.uc.uc_stack)) goto badframe; return regs->regs[0]; @@ -162,27 +178,36 @@ badframe: return 0; } -static int setup_sigframe(struct rt_sigframe __user *sf, +static int setup_sigframe(struct sigframe __user *sf, struct pt_regs *regs, sigset_t *set) { - int i, err = 0; - void *aux = sf->uc.uc_mcontext.__reserved; - struct _aarch64_ctx *end; + int err = 0; /* set up the stack frame for unwinding */ __put_user_error(regs->regs[29], &sf->fp, err); __put_user_error(regs->regs[30], &sf->lr, err); + err |= __copy_to_user(&sf->uc.uc_sigmask, set, sizeof(*set)); + err |= setup_sigcontext(&sf->uc.uc_mcontext, regs); + + return err; +} + +int setup_sigcontext(struct sigcontext __user *uc_mcontext, + struct pt_regs *regs) +{ + void *aux = uc_mcontext->__reserved; + struct _aarch64_ctx *end; + int i, err = 0; for (i = 0; i < 31; i++) - __put_user_error(regs->regs[i], &sf->uc.uc_mcontext.regs[i], + __put_user_error(regs->regs[i], &uc_mcontext->regs[i], err); - __put_user_error(regs->sp, &sf->uc.uc_mcontext.sp, err); - __put_user_error(regs->pc, &sf->uc.uc_mcontext.pc, err); - __put_user_error(regs->pstate, &sf->uc.uc_mcontext.pstate, err); - __put_user_error(current->thread.fault_address, &sf->uc.uc_mcontext.fault_address, err); + __put_user_error(regs->sp, &uc_mcontext->sp, err); + __put_user_error(regs->pc, &uc_mcontext->pc, err); + __put_user_error(regs->pstate, &uc_mcontext->pstate, err); - err |= __copy_to_user(&sf->uc.uc_sigmask, set, sizeof(*set)); + __put_user_error(current->thread.fault_address, &uc_mcontext->fault_address, err); if (err == 0) { struct fpsimd_context *fpsimd_ctx = @@ -229,14 +254,14 @@ static struct rt_sigframe __user *get_sigframe(struct ksignal *ksig, return frame; } -static void setup_return(struct pt_regs *regs, struct k_sigaction *ka, - void __user *frame, int usig) +void setup_return(struct pt_regs *regs, struct k_sigaction *ka, + void __user *frame, off_t fp_pos, int usig) { __sigrestore_t sigtramp; regs->regs[0] = usig; regs->sp = (unsigned long)frame; - regs->regs[29] = regs->sp + offsetof(struct rt_sigframe, fp); + regs->regs[29] = regs->sp + fp_pos; regs->pc = (unsigned long)ka->sa.sa_handler; if (ka->sa.sa_flags & SA_RESTORER) @@ -257,17 +282,17 @@ static int setup_rt_frame(int usig, struct ksignal *ksig, sigset_t *set, if (!frame) return 1; - __put_user_error(0, &frame->uc.uc_flags, err); - __put_user_error(NULL, &frame->uc.uc_link, err); + __put_user_error(0, &frame->sig.uc.uc_flags, err); + __put_user_error(NULL, &frame->sig.uc.uc_link, err); - err |= __save_altstack(&frame->uc.uc_stack, regs->sp); - err |= setup_sigframe(frame, regs, set); + err |= __save_altstack(&frame->sig.uc.uc_stack, regs->sp); + err |= setup_sigframe(&frame->sig, regs, set); if (err == 0) { - setup_return(regs, &ksig->ka, frame, usig); + setup_return(regs, &ksig->ka, frame, RT_SIGFRAME_FP_POS, usig); if (ksig->ka.sa.sa_flags & SA_SIGINFO) { err |= copy_siginfo_to_user(&frame->info, &ksig->info); regs->regs[1] = (unsigned long)&frame->info; - regs->regs[2] = (unsigned long)&frame->uc; + regs->regs[2] = (unsigned long)&frame->sig.uc; } }