• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "linker_gdb_support.h"
18 
19 #include <pthread.h>
20 
21 #include "private/ScopedPthreadMutexLocker.h"
22 
23 // This function is an empty stub where GDB locates a breakpoint to get notified
24 // about linker activity.
25 extern "C"
26 void __attribute__((noinline)) __attribute__((visibility("default"))) rtld_db_dlactivity();
27 
28 r_debug _r_debug =
29     {1, nullptr, reinterpret_cast<uintptr_t>(&rtld_db_dlactivity), r_debug::RT_CONSISTENT, 0};
30 
31 static pthread_mutex_t g__r_debug_mutex = PTHREAD_MUTEX_INITIALIZER;
32 static link_map* r_debug_tail = nullptr;
33 
insert_link_map_into_debug_map(link_map * map)34 void insert_link_map_into_debug_map(link_map* map) {
35   // Stick the new library at the end of the list.
36   // gdb tends to care more about libc than it does
37   // about leaf libraries, and ordering it this way
38   // reduces the back-and-forth over the wire.
39   if (r_debug_tail != nullptr) {
40     r_debug_tail->l_next = map;
41     map->l_prev = r_debug_tail;
42     map->l_next = nullptr;
43   } else {
44     _r_debug.r_map = map;
45     map->l_prev = nullptr;
46     map->l_next = nullptr;
47   }
48   r_debug_tail = map;
49 }
50 
remove_link_map_from_debug_map(link_map * map)51 void remove_link_map_from_debug_map(link_map* map) {
52   if (r_debug_tail == map) {
53     r_debug_tail = map->l_prev;
54   }
55 
56   if (map->l_prev) {
57     map->l_prev->l_next = map->l_next;
58   }
59   if (map->l_next) {
60     map->l_next->l_prev = map->l_prev;
61   }
62 }
63 
notify_gdb_of_load(link_map * map)64 void notify_gdb_of_load(link_map* map) {
65   ScopedPthreadMutexLocker locker(&g__r_debug_mutex);
66 
67   _r_debug.r_state = r_debug::RT_ADD;
68   rtld_db_dlactivity();
69 
70   insert_link_map_into_debug_map(map);
71 
72   _r_debug.r_state = r_debug::RT_CONSISTENT;
73   rtld_db_dlactivity();
74 }
75 
notify_gdb_of_unload(link_map * map)76 void notify_gdb_of_unload(link_map* map) {
77   ScopedPthreadMutexLocker locker(&g__r_debug_mutex);
78 
79   _r_debug.r_state = r_debug::RT_DELETE;
80   rtld_db_dlactivity();
81 
82   remove_link_map_from_debug_map(map);
83 
84   _r_debug.r_state = r_debug::RT_CONSISTENT;
85   rtld_db_dlactivity();
86 }
87 
notify_gdb_of_libraries()88 void notify_gdb_of_libraries() {
89   _r_debug.r_state = r_debug::RT_ADD;
90   rtld_db_dlactivity();
91   _r_debug.r_state = r_debug::RT_CONSISTENT;
92   rtld_db_dlactivity();
93 }
94 
95