Whamcloud - gitweb
b77d0bdbd07a839d4cc242a808b96d39ccef3fe9
[fs/lustre-release.git] / libcfs / libcfs / darwin / darwin-utils.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  * Copyright (C) 2002 Cluster File Systems, Inc.
5  * Author: Phil Schwan <phil@clusterfs.com>
6  *
7  * This file is part of Lustre, http://www.lustre.org.
8  *
9  * Lustre is free software; you can redistribute it and/or
10  * modify it under the terms of version 2 of the GNU General Public
11  * License as published by the Free Software Foundation.
12  *
13  * Lustre is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with Lustre; if not, write to the Free Software
20  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21  *
22  * Darwin porting library
23  * Make things easy to port
24  */
25 #define DEBUG_SUBSYSTEM S_LNET
26
27 #include <mach/mach_types.h>
28 #include <string.h>
29 #include <sys/errno.h>
30 #include <sys/types.h>
31 #include <sys/fcntl.h>
32 #include <lnet/types.h>
33
34 #include <libcfs/libcfs.h>
35
36 #ifndef isspace
37 inline int
38 isspace(char c)
39 {
40         return (c == ' ' || c == '\t' || c == '\n' || c == '\12');
41 }
42 #endif
43
44 char * strpbrk(const char * cs,const char * ct)
45 {
46         const char *sc1,*sc2;
47         
48         for( sc1 = cs; *sc1 != '\0'; ++sc1) {
49                 for( sc2 = ct; *sc2 != '\0'; ++sc2) {
50                         if (*sc1 == *sc2)
51                                 return (char *) sc1;
52                 }
53         }
54         return NULL;
55 }
56
57 char * strsep(char **s, const char *ct)
58 {
59         char *sbegin = *s, *end;
60         
61         if (sbegin == NULL)
62                 return NULL;
63         end = strpbrk(sbegin, ct);
64         if (end != NULL)
65                 *end++ = '\0';
66         *s = end;
67
68         return sbegin;
69 }
70
71 size_t strnlen(const char * s, size_t count)
72 {
73         const char *sc;
74
75         for (sc = s; count-- && *sc != '\0'; ++sc)
76                 /* nothing */;
77         return sc - s;
78 }
79
80 char *
81 strstr(const char *in, const char *str)
82 {
83         char c;
84         size_t len;
85         
86         c = *str++;
87         if (!c)
88                 return (char *) in;     // Trivial empty string case
89         len = strlen(str);
90         do {
91                 char sc;
92                 do {
93                         sc = *in++;
94                         if (!sc)
95                                 return (char *) 0;
96                 } while (sc != c);
97         } while (strncmp(in, str, len) != 0);
98         return (char *) (in - 1);
99 }
100
101 char *
102 strrchr(const char *p, int ch)
103 {
104         const char *end = p + strlen(p);
105         do {
106                 if (*end == (char)ch)
107                         return (char *)end;
108         } while (--end >= p);
109         return NULL;
110 }
111
112 char *
113 ul2dstr(unsigned long address, char *buf, int len)
114 {
115         char *pos = buf + len - 1;
116
117         if (len <= 0 || !buf)
118                 return NULL;
119         *pos = 0;
120         while (address) {
121                 if (!--len) break;
122                 *--pos = address % 10 + '0';
123                 address /= 10;
124         }
125         return pos;
126 }
127
128 /*
129  * miscellaneous libcfs stuff
130  */
131
132 /*
133  * Convert server error code to client format.
134  * Linux errno.h.
135  */
136
137 /* obtained by
138  *
139  *     cc /usr/include/asm/errno.h -E -dM | grep '#define E' | sort -n -k3,3
140  *
141  */
142 enum linux_errnos {
143         LINUX_EPERM              = 1,
144         LINUX_ENOENT             = 2,
145         LINUX_ESRCH              = 3,
146         LINUX_EINTR              = 4,
147         LINUX_EIO                = 5,
148         LINUX_ENXIO              = 6,
149         LINUX_E2BIG              = 7,
150         LINUX_ENOEXEC            = 8,
151         LINUX_EBADF              = 9,
152         LINUX_ECHILD             = 10,
153         LINUX_EAGAIN             = 11,
154         LINUX_ENOMEM             = 12,
155         LINUX_EACCES             = 13,
156         LINUX_EFAULT             = 14,
157         LINUX_ENOTBLK            = 15,
158         LINUX_EBUSY              = 16,
159         LINUX_EEXIST             = 17,
160         LINUX_EXDEV              = 18,
161         LINUX_ENODEV             = 19,
162         LINUX_ENOTDIR            = 20,
163         LINUX_EISDIR             = 21,
164         LINUX_EINVAL             = 22,
165         LINUX_ENFILE             = 23,
166         LINUX_EMFILE             = 24,
167         LINUX_ENOTTY             = 25,
168         LINUX_ETXTBSY            = 26,
169         LINUX_EFBIG              = 27,
170         LINUX_ENOSPC             = 28,
171         LINUX_ESPIPE             = 29,
172         LINUX_EROFS              = 30,
173         LINUX_EMLINK             = 31,
174         LINUX_EPIPE              = 32,
175         LINUX_EDOM               = 33,
176         LINUX_ERANGE             = 34,
177         LINUX_EDEADLK            = 35,
178         LINUX_ENAMETOOLONG       = 36,
179         LINUX_ENOLCK             = 37,
180         LINUX_ENOSYS             = 38,
181         LINUX_ENOTEMPTY          = 39,
182         LINUX_ELOOP              = 40,
183         LINUX_ENOMSG             = 42,
184         LINUX_EIDRM              = 43,
185         LINUX_ECHRNG             = 44,
186         LINUX_EL2NSYNC           = 45,
187         LINUX_EL3HLT             = 46,
188         LINUX_EL3RST             = 47,
189         LINUX_ELNRNG             = 48,
190         LINUX_EUNATCH            = 49,
191         LINUX_ENOCSI             = 50,
192         LINUX_EL2HLT             = 51,
193         LINUX_EBADE              = 52,
194         LINUX_EBADR              = 53,
195         LINUX_EXFULL             = 54,
196         LINUX_ENOANO             = 55,
197         LINUX_EBADRQC            = 56,
198         LINUX_EBADSLT            = 57,
199         LINUX_EBFONT             = 59,
200         LINUX_ENOSTR             = 60,
201         LINUX_ENODATA            = 61,
202         LINUX_ETIME              = 62,
203         LINUX_ENOSR              = 63,
204         LINUX_ENONET             = 64,
205         LINUX_ENOPKG             = 65,
206         LINUX_EREMOTE            = 66,
207         LINUX_ENOLINK            = 67,
208         LINUX_EADV               = 68,
209         LINUX_ESRMNT             = 69,
210         LINUX_ECOMM              = 70,
211         LINUX_EPROTO             = 71,
212         LINUX_EMULTIHOP          = 72,
213         LINUX_EDOTDOT            = 73,
214         LINUX_EBADMSG            = 74,
215         LINUX_EOVERFLOW          = 75,
216         LINUX_ENOTUNIQ           = 76,
217         LINUX_EBADFD             = 77,
218         LINUX_EREMCHG            = 78,
219         LINUX_ELIBACC            = 79,
220         LINUX_ELIBBAD            = 80,
221         LINUX_ELIBSCN            = 81,
222         LINUX_ELIBMAX            = 82,
223         LINUX_ELIBEXEC           = 83,
224         LINUX_EILSEQ             = 84,
225         LINUX_ERESTART           = 85,
226         LINUX_ESTRPIPE           = 86,
227         LINUX_EUSERS             = 87,
228         LINUX_ENOTSOCK           = 88,
229         LINUX_EDESTADDRREQ       = 89,
230         LINUX_EMSGSIZE           = 90,
231         LINUX_EPROTOTYPE         = 91,
232         LINUX_ENOPROTOOPT        = 92,
233         LINUX_EPROTONOSUPPORT    = 93,
234         LINUX_ESOCKTNOSUPPORT    = 94,
235         LINUX_EOPNOTSUPP         = 95,
236         LINUX_EPFNOSUPPORT       = 96,
237         LINUX_EAFNOSUPPORT       = 97,
238         LINUX_EADDRINUSE         = 98,
239         LINUX_EADDRNOTAVAIL      = 99,
240         LINUX_ENETDOWN           = 100,
241         LINUX_ENETUNREACH        = 101,
242         LINUX_ENETRESET          = 102,
243         LINUX_ECONNABORTED       = 103,
244         LINUX_ECONNRESET         = 104,
245         LINUX_ENOBUFS            = 105,
246         LINUX_EISCONN            = 106,
247         LINUX_ENOTCONN           = 107,
248         LINUX_ESHUTDOWN          = 108,
249         LINUX_ETOOMANYREFS       = 109,
250         LINUX_ETIMEDOUT          = 110,
251         LINUX_ECONNREFUSED       = 111,
252         LINUX_EHOSTDOWN          = 112,
253         LINUX_EHOSTUNREACH       = 113,
254         LINUX_EALREADY           = 114,
255         LINUX_EINPROGRESS        = 115,
256         LINUX_ESTALE             = 116,
257         LINUX_EUCLEAN            = 117,
258         LINUX_ENOTNAM            = 118,
259         LINUX_ENAVAIL            = 119,
260         LINUX_EISNAM             = 120,
261         LINUX_EREMOTEIO          = 121,
262         LINUX_EDQUOT             = 122,
263         LINUX_ENOMEDIUM          = 123,
264         LINUX_EMEDIUMTYPE        = 124,
265
266         /*
267          * we don't need these, but for completeness..
268          */
269         LINUX_EDEADLOCK          = LINUX_EDEADLK,
270         LINUX_EWOULDBLOCK        = LINUX_EAGAIN
271 };
272
273 int convert_server_error(__u64 ecode)
274 {
275         int sign;
276         int code;
277
278         static int errno_xlate[] = {
279                 /* success is always success */
280                 [0]                     = 0,
281                 [LINUX_EPERM]           = EPERM,
282                 [LINUX_ENOENT]          = ENOENT,
283                 [LINUX_ESRCH]           = ESRCH,
284                 [LINUX_EINTR]           = EINTR,
285                 [LINUX_EIO]             = EIO,
286                 [LINUX_ENXIO]           = ENXIO,
287                 [LINUX_E2BIG]           = E2BIG,
288                 [LINUX_ENOEXEC]         = ENOEXEC,
289                 [LINUX_EBADF]           = EBADF,
290                 [LINUX_ECHILD]          = ECHILD,
291                 [LINUX_EAGAIN]          = EAGAIN,
292                 [LINUX_ENOMEM]          = ENOMEM,
293                 [LINUX_EACCES]          = EACCES,
294                 [LINUX_EFAULT]          = EFAULT,
295                 [LINUX_ENOTBLK]         = ENOTBLK,
296                 [LINUX_EBUSY]           = EBUSY,
297                 [LINUX_EEXIST]          = EEXIST,
298                 [LINUX_EXDEV]           = EXDEV,
299                 [LINUX_ENODEV]          = ENODEV,
300                 [LINUX_ENOTDIR]         = ENOTDIR,
301                 [LINUX_EISDIR]          = EISDIR,
302                 [LINUX_EINVAL]          = EINVAL,
303                 [LINUX_ENFILE]          = ENFILE,
304                 [LINUX_EMFILE]          = EMFILE,
305                 [LINUX_ENOTTY]          = ENOTTY,
306                 [LINUX_ETXTBSY]         = ETXTBSY,
307                 [LINUX_EFBIG]           = EFBIG,
308                 [LINUX_ENOSPC]          = ENOSPC,
309                 [LINUX_ESPIPE]          = ESPIPE,
310                 [LINUX_EROFS]           = EROFS,
311                 [LINUX_EMLINK]          = EMLINK,
312                 [LINUX_EPIPE]           = EPIPE,
313                 [LINUX_EDOM]            = EDOM,
314                 [LINUX_ERANGE]          = ERANGE,
315                 [LINUX_EDEADLK]         = EDEADLK,
316                 [LINUX_ENAMETOOLONG]    = ENAMETOOLONG,
317                 [LINUX_ENOLCK]          = ENOLCK,
318                 [LINUX_ENOSYS]          = ENOSYS,
319                 [LINUX_ENOTEMPTY]       = ENOTEMPTY,
320                 [LINUX_ELOOP]           = ELOOP,
321                 [LINUX_ENOMSG]          = ENOMSG,
322                 [LINUX_EIDRM]           = EIDRM,
323                 [LINUX_ECHRNG]          = EINVAL /* ECHRNG */,
324                 [LINUX_EL2NSYNC]        = EINVAL /* EL2NSYNC */,
325                 [LINUX_EL3HLT]          = EINVAL /* EL3HLT */,
326                 [LINUX_EL3RST]          = EINVAL /* EL3RST */,
327                 [LINUX_ELNRNG]          = EINVAL /* ELNRNG */,
328                 [LINUX_EUNATCH]         = EINVAL /* EUNATCH */,
329                 [LINUX_ENOCSI]          = EINVAL /* ENOCSI */,
330                 [LINUX_EL2HLT]          = EINVAL /* EL2HLT */,
331                 [LINUX_EBADE]           = EINVAL /* EBADE */,
332                 [LINUX_EBADR]           = EBADRPC,
333                 [LINUX_EXFULL]          = EINVAL /* EXFULL */,
334                 [LINUX_ENOANO]          = EINVAL /* ENOANO */,
335                 [LINUX_EBADRQC]         = EINVAL /* EBADRQC */,
336                 [LINUX_EBADSLT]         = EINVAL /* EBADSLT */,
337                 [LINUX_EBFONT]          = EINVAL /* EBFONT */,
338                 [LINUX_ENOSTR]          = EINVAL /* ENOSTR */,
339                 [LINUX_ENODATA]         = EINVAL /* ENODATA */,
340                 [LINUX_ETIME]           = EINVAL /* ETIME */,
341                 [LINUX_ENOSR]           = EINVAL /* ENOSR */,
342                 [LINUX_ENONET]          = EINVAL /* ENONET */,
343                 [LINUX_ENOPKG]          = EINVAL /* ENOPKG */,
344                 [LINUX_EREMOTE]         = EREMOTE,
345                 [LINUX_ENOLINK]         = EINVAL /* ENOLINK */,
346                 [LINUX_EADV]            = EINVAL /* EADV */,
347                 [LINUX_ESRMNT]          = EINVAL /* ESRMNT */,
348                 [LINUX_ECOMM]           = EINVAL /* ECOMM */,
349                 [LINUX_EPROTO]          = EPROTOTYPE,
350                 [LINUX_EMULTIHOP]       = EINVAL /* EMULTIHOP */,
351                 [LINUX_EDOTDOT]         = EINVAL /* EDOTDOT */,
352                 [LINUX_EBADMSG]         = EINVAL /* EBADMSG */,
353                 [LINUX_EOVERFLOW]       = EOVERFLOW,
354                 [LINUX_ENOTUNIQ]        = EINVAL /* ENOTUNIQ */,
355                 [LINUX_EBADFD]          = EINVAL /* EBADFD */,
356                 [LINUX_EREMCHG]         = EINVAL /* EREMCHG */,
357                 [LINUX_ELIBACC]         = EINVAL /* ELIBACC */,
358                 [LINUX_ELIBBAD]         = EINVAL /* ELIBBAD */,
359                 [LINUX_ELIBSCN]         = EINVAL /* ELIBSCN */,
360                 [LINUX_ELIBMAX]         = EINVAL /* ELIBMAX */,
361                 [LINUX_ELIBEXEC]        = EINVAL /* ELIBEXEC */,
362                 [LINUX_EILSEQ]          = EILSEQ,
363                 [LINUX_ERESTART]        = EINVAL /* because ERESTART is
364                                                   * negative in XNU */,
365                 [LINUX_ESTRPIPE]        = EINVAL /* ESTRPIPE */,
366                 [LINUX_EUSERS]          = EUSERS,
367                 [LINUX_ENOTSOCK]        = ENOTSOCK,
368                 [LINUX_EDESTADDRREQ]    = EDESTADDRREQ,
369                 [LINUX_EMSGSIZE]        = EMSGSIZE,
370                 [LINUX_EPROTOTYPE]      = EPROTOTYPE,
371                 [LINUX_ENOPROTOOPT]     = ENOPROTOOPT,
372                 [LINUX_EPROTONOSUPPORT] = EPROTONOSUPPORT,
373                 [LINUX_ESOCKTNOSUPPORT] = ESOCKTNOSUPPORT,
374                 [LINUX_EOPNOTSUPP]      = EOPNOTSUPP,
375                 [LINUX_EPFNOSUPPORT]    = EPFNOSUPPORT,
376                 [LINUX_EAFNOSUPPORT]    = EAFNOSUPPORT,
377                 [LINUX_EADDRINUSE]      = EADDRINUSE,
378                 [LINUX_EADDRNOTAVAIL]   = EADDRNOTAVAIL,
379                 [LINUX_ENETDOWN]        = ENETDOWN,
380                 [LINUX_ENETUNREACH]     = ENETUNREACH,
381                 [LINUX_ENETRESET]       = ENETRESET,
382                 [LINUX_ECONNABORTED]    = ECONNABORTED,
383                 [LINUX_ECONNRESET]      = ECONNRESET,
384                 [LINUX_ENOBUFS]         = ENOBUFS,
385                 [LINUX_EISCONN]         = EISCONN,
386                 [LINUX_ENOTCONN]        = ENOTCONN,
387                 [LINUX_ESHUTDOWN]       = ESHUTDOWN,
388                 [LINUX_ETOOMANYREFS]    = ETOOMANYREFS,
389                 [LINUX_ETIMEDOUT]       = ETIMEDOUT,
390                 [LINUX_ECONNREFUSED]    = ECONNREFUSED,
391                 [LINUX_EHOSTDOWN]       = EHOSTDOWN,
392                 [LINUX_EHOSTUNREACH]    = EHOSTUNREACH,
393                 [LINUX_EALREADY]        = EALREADY,
394                 [LINUX_EINPROGRESS]     = EINPROGRESS,
395                 [LINUX_ESTALE]          = ESTALE,
396                 [LINUX_EUCLEAN]         = EINVAL /* EUCLEAN */,
397                 [LINUX_ENOTNAM]         = EINVAL /* ENOTNAM */,
398                 [LINUX_ENAVAIL]         = EINVAL /* ENAVAIL */,
399                 [LINUX_EISNAM]          = EINVAL /* EISNAM */,
400                 [LINUX_EREMOTEIO]       = EINVAL /* EREMOTEIO */,
401                 [LINUX_EDQUOT]          = EDQUOT,
402                 [LINUX_ENOMEDIUM]       = EINVAL /* ENOMEDIUM */,
403                 [LINUX_EMEDIUMTYPE]     = EINVAL /* EMEDIUMTYPE */,
404         };
405         code = (int)ecode;
406         if (code >= 0) {
407                 sign = +1;
408         } else {
409                 sign = -1;
410                 code = -code;
411         }
412         if (code < (sizeof errno_xlate) / (sizeof errno_xlate[0])) {
413                 code = errno_xlate[code];
414                 LASSERT(code >= 0);
415         }
416         return sign * code;
417 }
418
419 enum {
420         LINUX_O_RDONLY   =           00,
421         LINUX_O_WRONLY   =           01,
422         LINUX_O_RDWR     =           02,
423         LINUX_O_CREAT    =         0100,
424         LINUX_O_EXCL     =         0200,
425         LINUX_O_NOCTTY   =         0400,
426         LINUX_O_TRUNC    =        01000,
427         LINUX_O_APPEND   =        02000,
428         LINUX_O_NONBLOCK =        04000,
429         LINUX_O_NDELAY   =             LINUX_O_NONBLOCK,
430         LINUX_O_SYNC     =       010000,
431         LINUX_O_FSYNC    =             LINUX_O_SYNC,
432         LINUX_O_ASYNC    =       020000,
433         LINUX_O_DIRECT   =       040000,
434         LINUX_O_NOFOLLOW =      0400000
435 };
436
437 static inline void obit_convert(int *cflag, int *sflag,
438                                 unsigned cmask, unsigned smask)
439 {
440         if (*cflag & cmask != 0) {
441                 *sflag |= smask;
442                 *cflag &= ~cmask;
443         }
444 }
445
446 /*
447  * convert <fcntl.h> flag from XNU client to Linux _i386_ server.
448  */
449 int convert_client_oflag(int cflag, int *result)
450 {
451         int sflag = 0;
452
453         cflag = 0;
454         obit_convert(&cflag, &sflag, O_RDONLY,   LINUX_O_RDONLY);
455         obit_convert(&cflag, &sflag, O_WRONLY,   LINUX_O_WRONLY);
456         obit_convert(&cflag, &sflag, O_RDWR,     LINUX_O_RDWR);
457         obit_convert(&cflag, &sflag, O_NONBLOCK, LINUX_O_NONBLOCK);
458         obit_convert(&cflag, &sflag, O_APPEND,   LINUX_O_APPEND);
459         obit_convert(&cflag, &sflag, O_ASYNC,    LINUX_O_ASYNC);
460         obit_convert(&cflag, &sflag, O_FSYNC,    LINUX_O_FSYNC);
461         obit_convert(&cflag, &sflag, O_NOFOLLOW, LINUX_O_NOFOLLOW);
462         obit_convert(&cflag, &sflag, O_CREAT,    LINUX_O_CREAT);
463         obit_convert(&cflag, &sflag, O_TRUNC,    LINUX_O_TRUNC);
464         obit_convert(&cflag, &sflag, O_EXCL,     LINUX_O_EXCL);
465         obit_convert(&cflag, &sflag, O_CREAT,    LINUX_O_CREAT);
466         obit_convert(&cflag, &sflag, O_NDELAY,   LINUX_O_NDELAY);
467         obit_convert(&cflag, &sflag, O_NOCTTY,   LINUX_O_NOCTTY);
468         /*
469          * Some more obscure BSD flags have no Linux counterparts:
470          *
471          * O_SHLOCK     0x0010
472          * O_EXLOCK     0x0020
473          * O_EVTONLY    0x8000
474          * O_POPUP      0x80000000
475          * O_ALERT      0x20000000
476          */
477         if (cflag == 0) {
478                 *result = sflag;
479                 return 0;
480         } else
481                 return -EINVAL;
482 }
483
484 #ifdef __DARWIN8__
485 #else /* !__DARWIN8__ */
486 extern int unix_syscall();
487 extern int unix_syscall_return();
488
489 extern int ktrsysret();
490 extern int ktrace();
491
492 extern int ast_taken();
493 extern int ast_check();
494
495 extern int trap();
496 extern int syscall_trace();
497
498 static int is_addr_in_range(void *addr, void *start, void *end)
499 {
500         return start <= addr && addr <= end;
501 }
502
503 extern void cfs_thread_agent (void);
504
505 static int is_last_frame(void *addr)
506 {
507         if (addr == NULL)
508                 return 1;
509         else if (is_addr_in_range(addr, unix_syscall, unix_syscall_return))
510                 return 1;
511         else if (is_addr_in_range(addr, ktrsysret, ktrace))
512                 return 1;
513         else if (is_addr_in_range(addr, ast_taken, ast_check))
514                 return 1;
515         else if (is_addr_in_range(addr, trap, syscall_trace))
516                 return 1;
517         else if (is_addr_in_range(addr, cfs_thread_agent, cfs_kernel_thread))
518                 return 1;
519         else
520                 return 0;
521 }
522
523 static void *get_frame(int i)
524 {
525         void *result;
526
527 #define CASE(i) case (i): result = __builtin_return_address(i); break
528         switch (i + 1) {
529                 CASE(1);
530                 CASE(2);
531                 CASE(3);
532                 CASE(4);
533                 CASE(5);
534                 CASE(6);
535                 CASE(7);
536                 CASE(8);
537                 CASE(9);
538                 CASE(10);
539                 CASE(11);
540                 CASE(12);
541                 CASE(13);
542                 CASE(14);
543                 CASE(15);
544                 CASE(16);
545                 CASE(17);
546                 CASE(18);
547                 CASE(19);
548                 CASE(20);
549         default:
550                 panic("impossible frame number: %d\n", i);
551                 result = NULL;
552         }
553         return result;
554 }
555
556 void cfs_stack_trace_fill(struct cfs_stack_trace *trace)
557 {
558         int i;
559
560         memset(trace, 0, sizeof *trace);
561         for (i = 0; i < sizeof_array(trace->frame); ++ i) {
562                 void *addr;
563
564                 addr = get_frame(i);
565                 trace->frame[i] = addr;
566                 if (is_last_frame(addr))
567                         break;
568         }
569 }
570
571 void *cfs_stack_trace_frame(struct cfs_stack_trace *trace, int frame_no)
572 {
573         if (0 <= frame_no && frame_no < sizeof_array(trace->frame))
574                 return trace->frame[frame_no];
575         else
576                 return NULL;
577 }
578 #endif /* !__DARWIN8__ */