Message ID | OFE73EF236.0037C8EA-ON65258304.00227754-65258304.0023F29F@notes.na.collabserv.com |
---|---|
State | New, archived |
Headers |
Received: (qmail 60644 invoked by alias); 10 Sep 2018 06:32:51 -0000 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: <gdb-patches.sourceware.org> List-Unsubscribe: <mailto:gdb-patches-unsubscribe-##L=##H@sourceware.org> List-Subscribe: <mailto:gdb-patches-subscribe@sourceware.org> List-Archive: <http://sourceware.org/ml/gdb-patches/> List-Post: <mailto:gdb-patches@sourceware.org> List-Help: <mailto:gdb-patches-help@sourceware.org>, <http://sourceware.org/ml/#faqs> Sender: gdb-patches-owner@sourceware.org Delivered-To: mailing list gdb-patches@sourceware.org Received: (qmail 60634 invoked by uid 89); 10 Sep 2018 06:32:51 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-12.6 required=5.0 tests=BAYES_00, GIT_PATCH_2, GIT_PATCH_3, RCVD_IN_DNSWL_LOW, SPF_PASS autolearn=ham version=3.3.2 spammy=2018-09-07, 20180827, Supply, Hx-spam-relays-external:sk:2018091 X-HELO: mx0a-001b2d01.pphosted.com Received: from mx0b-001b2d01.pphosted.com (HELO mx0a-001b2d01.pphosted.com) (148.163.158.5) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Mon, 10 Sep 2018 06:32:47 +0000 Received: from pps.filterd (m0098421.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.16.0.22/8.16.0.22) with SMTP id w8A6TBsT010988 for <gdb-patches@sourceware.org>; Mon, 10 Sep 2018 02:32:45 -0400 Received: from smtp.notes.na.collabserv.com (smtp.notes.na.collabserv.com [192.155.248.75]) by mx0a-001b2d01.pphosted.com with ESMTP id 2mdf1js0fx-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT) for <gdb-patches@sourceware.org>; Mon, 10 Sep 2018 02:32:45 -0400 Received: from localhost by smtp.notes.na.collabserv.com with smtp.notes.na.collabserv.com ESMTP for <gdb-patches@sourceware.org> from <sangamesh.swamy@in.ibm.com>; Mon, 10 Sep 2018 06:32:44 -0000 Received: from us1a3-smtp07.a3.dal06.isc4sb.com (10.146.103.14) by smtp.notes.na.collabserv.com (10.106.227.123) with smtp.notes.na.collabserv.com ESMTP; Mon, 10 Sep 2018 06:32:40 -0000 Received: from us1a3-mail142.a3.dal06.isc4sb.com ([10.146.38.78]) by us1a3-smtp07.a3.dal06.isc4sb.com with ESMTP id 2018091006324010-112582 ; Mon, 10 Sep 2018 06:32:40 +0000 In-Reply-To: <20180904161827.7049008a@pinnacle.lan> To: Kevin Buettner <kevinb@redhat.com> Cc: gdb-patches@sourceware.org Subject: Re: [PATCH] Adding support for reding signal handler frame in AIX From: "Sangamesh Mallayya" <sangamesh.swamy@in.ibm.com> Date: Mon, 10 Sep 2018 12:02:38 +0530 References: <OF4A567E9C.67455645-ON652582F8.001F64A7-652582F8.00207854@notes.na.collabserv.com> <20180904161827.7049008a@pinnacle.lan> MIME-Version: 1.0 X-KeepSent: E73EF236:0037C8EA-65258304:00227754; type=4; name=$KeepSent X-LLNOutbound: False X-Disclaimed: 31307 X-TNEFEvaluated: 1 x-cbid: 18091006-3815-0000-0000-00000810148F X-IBM-SpamModules-Scores: BY=0; FL=0; FP=0; FZ=0; HX=0; KW=0; PH=0; SC=0.425523; ST=0; TS=0; UL=0; ISC=; MB=0.122080 X-IBM-SpamModules-Versions: BY=3.00009694; HX=3.00000242; KW=3.00000007; PH=3.00000004; SC=3.00000266; SDB=6.01086150; UDB=6.00560755; IPR=6.00866161; BA=6.00006093; NDR=6.00000001; ZLA=6.00000005; ZF=6.00000009; ZB=6.00000000; ZP=6.00000000; ZH=6.00000000; ZU=6.00000002; MB=3.00023206; XFM=3.00000015; UTC=2018-09-10 06:32:43 X-IBM-AV-DETECTION: SAVI=unsuspicious REMOTE=unsuspicious XFE=unused X-IBM-AV-VERSION: SAVI=2018-09-10 02:08:35 - 6.00008946 x-cbparentid: 18091006-3816-0000-0000-0000BFC41EFE Message-Id: <OFE73EF236.0037C8EA-ON65258304.00227754-65258304.0023F29F@notes.na.collabserv.com> Content-Type: text/plain; charset="US-ASCII" Content-Transfer-Encoding: quoted-printable X-Proofpoint-Spam-Reason: safe |
Commit Message
Sangamesh Mallayya
Sept. 10, 2018, 6:32 a.m. UTC
Hi Kevin, Thanks a lot for review and comments. > > + sigconext structure have the mstsave saved under the > > typo, I think - s/sigconext/sigcontext/ > Yes. Will correct this. > > + sc_jmpbuf.jmp_context. STKMIN(minimum stack size) is 56 for 32-bit > > + processes, and iar offset under sc_jmpbuf.jmp_context is 40. > > + ie offsetof(struct sigcontext, sc_jmpbuf.jmp_context.iar). > > + so PC offset in this case is STKMIN+iar offset, which is 96 */ > > Please add a period at the end of this sentence. > Sure. > > + > > #define SIG_FRAME_PC_OFFSET 96 > > #define SIG_FRAME_LR_OFFSET 108 > > +/* STKMIN+grp1 offset, which is 56+228=284 */ > > #define SIG_FRAME_FP_OFFSET 284 > > > > +/* 64 bit process > > + STKMIN64 is 112 and iar offset is 312. So 112+312=424 */ > > +#define SIG_FRAME_LR_OFFSET64 424 > > +/* STKMIN64+grp1 offset. 112+56=168 */ > > +#define SIG_FRAME_FP_OFFSET64 168 > > > > /* Core file support. */ > > > > @@ -103,6 +118,104 @@ > > -1 /* vrsave_offset */ > > }; > > > > +static void > > +aix_sigtramp_cache (struct frame_info *this_frame, > > + struct trad_frame_cache *this_cache, > > + CORE_ADDR func, LONGEST offset, > > + int bias) > > +{ > > + LONGEST backchain; > > + CORE_ADDR base, frame_base, base_orig; > > + CORE_ADDR regs; > > + CORE_ADDR gpregs; > > + CORE_ADDR fpregs; > > + int i; > > + struct gdbarch *gdbarch = get_frame_arch (this_frame); > > + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); > > + int wordsize = tdep->wordsize; > > + enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); > > + > > + base = get_frame_register_unsigned (this_frame, > > + gdbarch_sp_regnum (gdbarch)); > > + base_orig = base; > > + if (wordsize == 4) { > > + safe_read_memory_integer (base_orig + SIG_FRAME_FP_OFFSET + 8, > > + wordsize, byte_order, &backchain); > > + base = (CORE_ADDR)backchain; > > + } else { > > + safe_read_memory_integer (base_orig + SIG_FRAME_FP_OFFSET64, > > + wordsize, byte_order, &backchain); > > + base = (CORE_ADDR)backchain; > > + } > > I'm wondering if the cast might be avoided by using > read_memory_typed_address in place of safe_read_memory_integer? > That way you'd be able to assign directly to base and also be > able to eliminate the "backchain" variable. > read_memory_typed_address requires the second parameter of *type. Need to check and confirm how easy to get type, and does it required more function calls than just calling safe_read_memory_integer would be good. > > + > > + trad_frame_set_reg_value (this_cache, gdbarch_pc_regnum (gdbarch), func); > > + trad_frame_set_reg_value (this_cache, gdbarch_sp_regnum (gdbarch), base); > > + > > + if (wordsize == 4) { > > + trad_frame_set_reg_addr (this_cache, tdep->ppc_lr_regnum, > > + base_orig + offset + 52 + 8); > > + } else { > > + trad_frame_set_reg_addr (this_cache, tdep->ppc_lr_regnum, > > + base_orig + offset + 320); > > + } > > + trad_frame_set_id (this_cache, frame_id_build (base, func)); > > +} > > + > > +static void > > +aix_sigtramp_cache_init (const struct tramp_frame *self, > > + struct frame_info *this_frame, > > + struct trad_frame_cache *this_cache, > > + CORE_ADDR func) > > +{ > > + struct gdbarch *gdbarch = get_frame_arch (this_frame); > > + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); > > + > > + if (tdep->wordsize == 4) > > + aix_sigtramp_cache (this_frame, this_cache, func, > > + 0x38 /* Minimum stack size */, > > + 0); > > + else > > + aix_sigtramp_cache (this_frame, this_cache, func, > > + 0x70 /* Minimum stack size. */, > > + 0); > > +} > > + > > +static int > > +aix_validate_pc (const struct tramp_frame *self, > > + struct frame_info *this_frame, > > + CORE_ADDR *pc) > > +{ > > + struct gdbarch *gdbarch = get_frame_arch (this_frame); > > + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); > > + enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); > > + CORE_ADDR dest, frame_base; > > + frame_base = get_frame_register_unsigned (this_frame, > > + gdbarch_sp_regnum (gdbarch)); > > + if (tdep->wordsize == 4) { > > + if (*pc && *pc < AIX_TEXT_SEGMENT_BASE) { > > + *pc = read_memory_unsigned_integer > > + (frame_base + SIG_FRAME_PC_OFFSET + 8, > > + tdep->wordsize, byte_order); > > + } > > + } else { > > + if (*pc && *pc < AIX_TEXT_SEGMENT_BASE) { > > + *pc = read_memory_unsigned_integer > > + (frame_base + SIG_FRAME_LR_OFFSET64, > > + tdep->wordsize, byte_order); > > + } > > + } > > + return 1; > > +} > > + > > +static struct tramp_frame aix_sighandler_tramp_frame = { > > + SIGTRAMP_FRAME, > > + 4, > > + { > > + { TRAMP_SENTINEL_INSN }, > > + }, > > + aix_sigtramp_cache_init, > > + aix_validate_pc > > +}; > > > > /* Supply register REGNUM in the general-purpose register set REGSET > > from the buffer specified by GREGS and LEN to register cache > > @@ -1083,6 +1196,7 @@ > > set_gdbarch_auto_wide_charset (gdbarch, rs6000_aix_auto_wide_charset); > > > > set_solib_ops (gdbarch, &solib_aix_so_ops); > > + tramp_frame_prepend_unwinder (gdbarch, &aix_sighandler_tramp_frame); > > } > > > > void > > --- ./gdb/tramp-frame.c_orig 2018-08-27 03:25:49 +0000 > > +++ ./gdb/tramp-frame.c 2018-08-27 03:26:24 +0000 > > @@ -132,6 +132,12 @@ > > false on HPUX which has a signal trampoline that has a name; it can > > also be false when using an alternative signal stack. */ > > func = tramp_frame_start (tramp, this_frame, pc); > > + #if defined (_AIX) > > + if (pc <= 0x10000000) { > > + tramp->validate (tramp, this_frame, &pc); > > + func = pc; > > + } > > + #endif > > We don't want to be putting OS specific ifdefs here. It seems to me > that the pc <= 0x10000000 test could be put in the validate code if in > fact it's needed at all. The return value of that call to validate is > not being checked, so that means that you're calling it to obtain > func. But func should be correctly set by the call to > tramp_frame_start, earlier on. Note, too, that tramp_frame_start > calls the validate method, so it seems to me that it ought to be > possible to get it set as needed by some suitable definition of > validate. > Yes. Thanks! Earlier code was calling validate function twice which wasn't required. We can remove that AIX ifdef and i have made the below changes. Rest all are same. Let me know your view on this. # diff -u tramp-frame.c_orig tramp-frame.c static struct tramp_frame aix_sighandler_tramp_frame = { SIGTRAMP_FRAME, 4, { { TRAMP_SENTINEL_INSN, -1}, { AIX_TRAMP_SENTINEL_INSN, -2}, <====== New definition to make sure this check is done only when running it on AIX. }, aix_sigtramp_cache_init, aix_validate_pc };
Comments
On Mon, 10 Sep 2018 12:02:38 +0530 "Sangamesh Mallayya" <sangamesh.swamy@in.ibm.com> wrote: > > > --- ./gdb/tramp-frame.c_orig 2018-08-27 03:25:49 +0000 > > > +++ ./gdb/tramp-frame.c 2018-08-27 03:26:24 +0000 > > > @@ -132,6 +132,12 @@ > > > false on HPUX which has a signal trampoline that has a name; it > can > > > also be false when using an alternative signal stack. */ > > > func = tramp_frame_start (tramp, this_frame, pc); > > > + #if defined (_AIX) > > > + if (pc <= 0x10000000) { > > > + tramp->validate (tramp, this_frame, &pc); > > > + func = pc; > > > + } > > > + #endif > > > > We don't want to be putting OS specific ifdefs here. It seems to me > > that the pc <= 0x10000000 test could be put in the validate code if in > > fact it's needed at all. The return value of that call to validate is > > not being checked, so that means that you're calling it to obtain > > func. But func should be correctly set by the call to > > tramp_frame_start, earlier on. Note, too, that tramp_frame_start > > calls the validate method, so it seems to me that it ought to be > > possible to get it set as needed by some suitable definition of > > validate. > > > > Yes. Thanks! > Earlier code was calling validate function twice which wasn't required. > We can remove that AIX ifdef and i have made the below changes. Rest all > are same. > Let me know your view on this. > > # diff -u tramp-frame.c_orig tramp-frame.c > --- tramp-frame.c_orig 2018-08-27 03:25:49 +0000 > +++ tramp-frame.c 2018-09-07 10:20:09 +0000 > @@ -86,11 +86,15 @@ > struct gdbarch *gdbarch = get_frame_arch (this_frame); > enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); > int ti; > + CORE_ADDR old_pc = pc; > > /* Check if we can use this trampoline. */ > if (tramp->validate && !tramp->validate (tramp, this_frame, &pc)) > return 0; > - > + if ((tramp->insn[0].bytes == TRAMP_SENTINEL_INSN) && > + (tramp->insn[1].bytes == AIX_TRAMP_SENTINEL_INSN) && > + (old_pc < 0x1000000)) > + return pc; Even though you've gotten rid of the ifdefs, my earlier comment, which I've left intact above, still applies. We should not be putting OS/target specific code into tramp-frame.c. I still think it should be possible to do what you want via a suitable definition of the validate method for AIX. I.e. the place to make these changes is in rs6000-aix-tdep.c. If we don't have the infrastructure to do what you need, then the infrastructure needs to be extended so that you have the requisite hooks to be able to place the OS dependent code into the correct tdep file. However, before that happens, I'd like to understand why it's not possible to do what you require via some change to AIX's validate method. Kevin
Thanks Ulrich and kevin for the review and comments. Sorry for the late reply as i was off due to personal emergency. I will have look at the suggestions and implement the new changes. Thanks, Sangamesh From: "Ulrich Weigand" <uweigand@de.ibm.com> To: Sangamesh Mallayya/India/IBM@IBMIN Cc: kevinb@redhat.com (Kevin Buettner), gdb-patches@sourceware.org Date: 09/12/2018 07:23 PM Subject: Re: [PATCH] Adding support for reding signal handler frame in AIX Sangamesh Mallayya wrote: > Yes. Thanks! > Earlier code was calling validate function twice which wasn't required. > We can remove that AIX ifdef and i have made the below changes. Rest all=20 > are same. > Let me know your view on this. > > # diff -u tramp-frame.c_orig tramp-frame.c > --- tramp-frame.c_orig 2018-08-27 03:25:49 +0000 > +++ tramp-frame.c 2018-09-07 10:20:09 +0000 > @@ -86,11 +86,15 @@ > struct gdbarch *gdbarch =3D get_frame_arch (this_frame); > enum bfd_endian byte_order =3D gdbarch_byte_order (gdbarch); > int ti; > + CORE_ADDR old_pc =3D pc; > =20 > /* Check if we can use this trampoline. */ > if (tramp->validate && !tramp->validate (tramp, this_frame, &pc)) > return 0; > - > + if ((tramp->insn[0].bytes =3D=3D TRAMP_SENTINEL_INSN) && > + (tramp->insn[1].bytes =3D=3D AIX_TRAMP_SENTINEL_INSN) && > + (old_pc < 0x1000000)) > + return pc; I agree with Kevin that code like this shouldn't be in common code. It looks like the underlying problem is that tramp-frame isn't a good match for what you're trying to do: tramp-frame tries to detect trampolines by matching well-known *code sequences*. However, you don't actually have any code sequence to match, but want to identify trampolines solely by their PC. Since you pass no code sequence to the tramp-frame matcher, it will actually never match. I'd suggest the best way forward is to not actually use tramp-frame at all then, but just write your own matcher based directly on a trad-frame cache. An example to look at might be s390_stub_frame_unwind. Along those lines, you can implement a sniffer that checks for special PC value (and possibly a backchain zero check in addition), and then implement this_id and prev_register routines based on a trad-frame register cache (you should be able to use the aix_sigtramp_cache routine in your patch as-is for that part). Bye, Ulrich
Hi Ulrich/Kevin, I have modified the patch and implemented it using the trad frame cache. Please review and let me know the comments. Here is the dwarf test results summary. Right now gdb isn't properly able to debug stabs binary which i will be debugging. Without patch ============= # of expected passes 18912 # of unexpected failures 2289 # of expected failures 14 # of known failures 17 # of unresolved testcases 29 # of untested testcases 64 # of unsupported tests 37 With patch ========== # of expected passes 18936 # of unexpected failures 2265 # of expected failures 14 # of known failures 17 # of unresolved testcases 27 # of untested testcases 65 # of unsupported tests 37 Thanks, Sangamesh From: Sangamesh Mallayya/India/IBM To: "Ulrich Weigand" <uweigand@de.ibm.com> Cc: gdb-patches@sourceware.org, kevinb@redhat.com (Kevin Buettner) Date: 09/27/2018 02:03 PM Subject: Re: [PATCH] Adding support for reding signal handler frame in AIX Thanks Ulrich and kevin for the review and comments. Sorry for the late reply as i was off due to personal emergency. I will have look at the suggestions and implement the new changes. Thanks, Sangamesh From: "Ulrich Weigand" <uweigand@de.ibm.com> To: Sangamesh Mallayya/India/IBM@IBMIN Cc: kevinb@redhat.com (Kevin Buettner), gdb-patches@sourceware.org Date: 09/12/2018 07:23 PM Subject: Re: [PATCH] Adding support for reding signal handler frame in AIX Sangamesh Mallayya wrote: > Yes. Thanks! > Earlier code was calling validate function twice which wasn't required. > We can remove that AIX ifdef and i have made the below changes. Rest all=20 > are same. > Let me know your view on this. > > # diff -u tramp-frame.c_orig tramp-frame.c > --- tramp-frame.c_orig 2018-08-27 03:25:49 +0000 > +++ tramp-frame.c 2018-09-07 10:20:09 +0000 > @@ -86,11 +86,15 @@ > struct gdbarch *gdbarch =3D get_frame_arch (this_frame); > enum bfd_endian byte_order =3D gdbarch_byte_order (gdbarch); > int ti; > + CORE_ADDR old_pc =3D pc; > =20 > /* Check if we can use this trampoline. */ > if (tramp->validate && !tramp->validate (tramp, this_frame, &pc)) > return 0; > - > + if ((tramp->insn[0].bytes =3D=3D TRAMP_SENTINEL_INSN) && > + (tramp->insn[1].bytes =3D=3D AIX_TRAMP_SENTINEL_INSN) && > + (old_pc < 0x1000000)) > + return pc; I agree with Kevin that code like this shouldn't be in common code. It looks like the underlying problem is that tramp-frame isn't a good match for what you're trying to do: tramp-frame tries to detect trampolines by matching well-known *code sequences*. However, you don't actually have any code sequence to match, but want to identify trampolines solely by their PC. Since you pass no code sequence to the tramp-frame matcher, it will actually never match. I'd suggest the best way forward is to not actually use tramp-frame at all then, but just write your own matcher based directly on a trad-frame cache. An example to look at might be s390_stub_frame_unwind. Along those lines, you can implement a sniffer that checks for special PC value (and possibly a backchain zero check in addition), and then implement this_id and prev_register routines based on a trad-frame register cache (you should be able to use the aix_sigtramp_cache routine in your patch as-is for that part). Bye, Ulrich
Hi Ulrich, Thanks for the review. > > > I have modified the patch and implemented it using the trad frame cache. > > Please review and let me know the comments. > > This version now looks pretty good to me, I just have a few minor comments > related to coding style. Once those are addresses, it should be ready to > commit. > > > + sigconext structure have the mstsave saved under the > > Typo "sigcontext" ? > Yes. Corrected this. > > + if (wordsize == 4) { > > + func = read_memory_unsigned_integer (base_orig + > > + SIG_FRAME_PC_OFFSET + 8, > > + tdep->wordsize, byte_order); > > + safe_read_memory_integer (base_orig + SIG_FRAME_FP_OFFSET + 8, > > + wordsize, byte_order, &backchain); > > + base = (CORE_ADDR)backchain; > > + } else { > > + func = read_memory_unsigned_integer (base_orig + > > + SIG_FRAME_LR_OFFSET64, > > + tdep->wordsize, byte_order); > > + safe_read_memory_integer (base_orig + SIG_FRAME_FP_OFFSET64, > > + wordsize, byte_order, &backchain); > > + base = (CORE_ADDR)backchain; > > + } > > GNU coding style is to put braces on separate lines, and indent like so > > if (wordsize == 4) > { > func = ... > } > else > { > func = ... > } > Changed to have the proper coding style. > Also, why do you use tdep->wordsize in some places and wordsize in others? > Now using only tdep->wordsize. > > + if (wordsize == 4) { > > + trad_frame_set_reg_addr (this_trad_cache, tdep->ppc_lr_regnum, > > + base_orig + 0x38 + 52 + 8); > > + } else { > > + trad_frame_set_reg_addr (this_trad_cache, tdep->ppc_lr_regnum, > > + base_orig + 0x70 + 320); > > + } > > Where there is just a single line inside the if / else block, you > should just omit the braces completely. > Removed the extra braces. > > * gdb.base/aix-sighandle_test.c: New file. > > * gdb.base/aix-sighandle_test.exp: New file. > > Those should best go in gdb.arch, not in gdb.base (since they are > specific to a single platform). Also, it may be better to omit > the "_test" part of the file names (all files in these directories > are tests!). > Moved these to gdb.arch. Attaching the modified files. Please review and let me know if fine to commit.
--- tramp-frame.c_orig 2018-08-27 03:25:49 +0000 +++ tramp-frame.c 2018-09-07 10:20:09 +0000 @@ -86,11 +86,15 @@ struct gdbarch *gdbarch = get_frame_arch (this_frame); enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); int ti; + CORE_ADDR old_pc = pc; /* Check if we can use this trampoline. */ if (tramp->validate && !tramp->validate (tramp, this_frame, &pc)) return 0; - + if ((tramp->insn[0].bytes == TRAMP_SENTINEL_INSN) && + (tramp->insn[1].bytes == AIX_TRAMP_SENTINEL_INSN) && + (old_pc < 0x1000000)) + return pc; --- tramp-frame.h_orig 2018-09-07 10:03:34 +0000 +++ tramp-frame.h 2018-09-07 10:18:50 +0000 @@ -42,6 +42,7 @@ /* Magic instruction that to mark the end of the signal trampoline instruction sequence. */ #define TRAMP_SENTINEL_INSN ((LONGEST) -1) +#define AIX_TRAMP_SENTINEL_INSN ((LONGEST) -2) <====== New definition to make sure this check is done only when running it on AIX.