1/* libunwind - a platform-independent unwind library
2   Copyright (C) 2014 The Android Open Source Project
3
4This file is part of libunwind.
5
6Permission is hereby granted, free of charge, to any person obtaining
7a copy of this software and associated documentation files (the
8"Software"), to deal in the Software without restriction, including
9without limitation the rights to use, copy, modify, merge, publish,
10distribute, sublicense, and/or sell copies of the Software, and to
11permit persons to whom the Software is furnished to do so, subject to
12the following conditions:
13
14The above copyright notice and this permission notice shall be
15included in all copies or substantial portions of the Software.
16
17THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */
24
25#define UNW_LOCAL_ONLY
26#include <libunwind.h>
27#include "libunwind_i.h"
28
29/* Globals to hold the map data for local unwinds. */
30HIDDEN struct map_info *local_map_list = NULL;
31HIDDEN int local_map_list_refs = 0;
32HIDDEN lock_rdwr_var (local_rdwr_lock);
33
34PROTECTED void
35unw_map_local_cursor_get (unw_map_cursor_t *map_cursor)
36{
37  intrmask_t saved_mask;
38
39  /* This function can be called before any other unwind code, so make sure
40     the lock has been initialized.  */
41  map_local_init ();
42
43  lock_rdwr_wr_acquire (&local_rdwr_lock, saved_mask);
44  map_cursor->map_list = local_map_list;
45  map_cursor->cur_map = local_map_list;
46  lock_rdwr_release (&local_rdwr_lock, saved_mask);
47}
48
49PROTECTED int
50unw_map_local_cursor_valid (unw_map_cursor_t *map_cursor)
51{
52  if (map_cursor->map_list == local_map_list)
53    return 0;
54  return -1;
55}
56
57PROTECTED int
58unw_map_local_create (void)
59{
60  intrmask_t saved_mask;
61  int ret_value = 0;
62
63  /* This function can be called before any other unwind code, so make sure
64     the lock has been initialized.  */
65  map_local_init ();
66
67  lock_rdwr_wr_acquire (&local_rdwr_lock, saved_mask);
68  if (local_map_list_refs == 0)
69    {
70      local_map_list = map_create_list (getpid());
71      if (local_map_list != NULL)
72        local_map_list_refs = 1;
73      else
74        ret_value = -1;
75    }
76  else
77    local_map_list_refs++;
78  lock_rdwr_release (&local_rdwr_lock, saved_mask);
79  return ret_value;
80}
81
82PROTECTED void
83unw_map_local_destroy (void)
84{
85  intrmask_t saved_mask;
86
87  /* This function can be called before any other unwind code, so make sure
88     the lock has been initialized.  */
89  map_local_init ();
90
91  lock_rdwr_wr_acquire (&local_rdwr_lock, saved_mask);
92  if (local_map_list != NULL && --local_map_list_refs == 0)
93    {
94      map_destroy_list (local_map_list);
95      local_map_list = NULL;
96    }
97  lock_rdwr_release (&local_rdwr_lock, saved_mask);
98}
99
100PROTECTED int
101unw_map_local_cursor_get_next (unw_map_cursor_t *map_cursor, unw_map_t *unw_map)
102{
103  struct map_info *map_info = map_cursor->cur_map;
104  intrmask_t saved_mask;
105  int ret = 1;
106
107  if (map_info == NULL)
108    return 0;
109
110  /* This function can be called before any other unwind code, so make sure
111     the lock has been initialized.  */
112  map_local_init ();
113
114  lock_rdwr_rd_acquire (&local_rdwr_lock, saved_mask);
115  if (map_cursor->map_list != local_map_list)
116    {
117      map_cursor->map_list = local_map_list;
118      ret = -UNW_EINVAL;
119    }
120  else
121    {
122      unw_map->start = map_info->start;
123      unw_map->end = map_info->end;
124      unw_map->flags = map_info->flags;
125      if (map_info->path)
126        unw_map->path = strdup (map_info->path);
127      else
128        unw_map->path = NULL;
129
130      map_cursor->cur_map = map_info->next;
131    }
132  lock_rdwr_release (&local_rdwr_lock, saved_mask);
133
134  return ret;
135}
136