First pass at thread_db integration for FreeBSD.
[dyninst.git] / common / src / freebsdKludges.C
1 /*
2  * Copyright (c) 1996-2009 Barton P. Miller
3  * 
4  * We provide the Paradyn Parallel Performance Tools (below
5  * described as "Paradyn") on an AS IS basis, and do not warrant its
6  * validity or performance.  We reserve the right to update, modify,
7  * or discontinue this software at any time.  We shall have no
8  * obligation to supply such updates or modifications or any other
9  * form of support to you.
10  * 
11  * By your use of Paradyn, you understand and agree that we (or any
12  * other person or entity with proprietary rights in Paradyn) are
13  * under no obligation to provide either maintenance services,
14  * update services, notices of latent defects, or correction of
15  * defects for Paradyn.
16  * 
17  * This library is free software; you can redistribute it and/or
18  * modify it under the terms of the GNU Lesser General Public
19  * License as published by the Free Software Foundation; either
20  * version 2.1 of the License, or (at your option) any later version.
21  * 
22  * This library is distributed in the hope that it will be useful,
23  * but WITHOUT ANY WARRANTY; without even the implied warranty of
24  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
25  * Lesser General Public License for more details.
26  * 
27  * You should have received a copy of the GNU Lesser General Public
28  * License along with this library; if not, write to the Free Software
29  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
30  */
31
32 #include "common/h/headers.h"
33 #include <sys/sysctl.h>
34 #include <sys/types.h>
35 #include <sys/user.h>
36 #include <sys/ptrace.h>
37 #include <libutil.h>
38
39 char * P_cplus_demangle( const char * symbol, bool,
40                                 bool includeTypes ) 
41 {
42    int opts = 0;
43    opts |= includeTypes ? DMGL_PARAMS | DMGL_ANSI : 0;
44
45    char * demangled = cplus_demangle( const_cast< char *>(symbol), opts);
46    if( demangled == NULL ) { return NULL; }
47
48    if( ! includeTypes ) {
49         /* de-demangling never increases the length */   
50         char * dedemangled = strdup( demangled );   
51         assert( dedemangled != NULL );
52         dedemangle( demangled, dedemangled );
53         assert( dedemangled != NULL );
54
55         free( demangled );
56         return dedemangled;
57    }
58
59    return demangled;
60 }
61
62 // Process Information Queries //
63 // No procfs mounted by default -- need to rely on sysctl //
64
65 /*
66  * Gets the full path of the executable for the specified process
67  *
68  * pid  The pid for the process
69  *
70  * Returns the full path (caller is responsible for free'ing)
71  */
72 char *sysctl_getExecPathname(pid_t pid) {
73     int mib[4];
74     mib[0] = CTL_KERN;
75     mib[1] = KERN_PROC;
76     mib[2] = KERN_PROC_PATHNAME;
77     mib[3] = pid;
78
79     size_t length;
80     if( sysctl(mib, 4, NULL, &length, NULL, 0) ) {
81         return NULL;
82     }
83
84     char *pathname = (char *)calloc(length, sizeof(char));
85
86     if( !pathname ) return NULL;
87
88     if( sysctl(mib, 4, pathname, &length, NULL, 0) ) {
89         free(pathname);
90         return NULL;
91     }
92
93     return pathname;
94 }
95
96 static struct kinfo_proc *getProcInfo(pid_t pid, size_t &length, bool getThreads) {
97     int mib[4];
98     mib[0] = CTL_KERN;
99     mib[1] = KERN_PROC;
100     mib[2] = KERN_PROC_PID | ( getThreads ? KERN_PROC_INC_THREAD : 0 );
101     mib[3] = pid;
102
103     if( sysctl(mib, 4, NULL, &length, NULL, 0) ) {
104         return NULL;
105     }
106
107     struct kinfo_proc *procInfo = (struct kinfo_proc *)malloc(length);
108     if( !procInfo ) return NULL;
109
110     if( sysctl(mib, 4, procInfo, &length, NULL, 0) ) {
111         free(procInfo);
112         return NULL;
113     }
114
115     assert( length > 0 && "process information not parsed correctly" );
116
117     return procInfo;
118 }
119
120 map_entries *getVMMaps(int pid, unsigned &maps_size) {
121     const int VM_PATH_MAX = 512;
122     struct kinfo_vmentry *maps;
123     map_entries *retMaps;
124
125     maps = kinfo_getvmmap(pid, (int *)&maps_size);
126     if( !maps ) {
127         return NULL;
128     }
129
130     retMaps = (map_entries *)calloc(maps_size, sizeof(map_entries));
131     if( !retMaps ) {
132         free(maps);
133         return NULL;
134     }
135
136     // Translate from one structure to another
137     for(unsigned i = 0; i < maps_size; ++i) {
138         retMaps[i].start = maps[i].kve_start;
139         retMaps[i].end = maps[i].kve_end;
140         retMaps[i].offset = maps[i].kve_offset; 
141         retMaps[i].dev_major = 0; // N/A
142         retMaps[i].dev_minor = 0; // N/A
143         retMaps[i].inode = maps[i].kve_fileid;
144
145         retMaps[i].prems = 0;
146         if( KVME_PROT_READ & maps[i].kve_protection ) {
147             retMaps[i].prems |= PREMS_READ;
148         }
149
150         if( KVME_PROT_WRITE & maps[i].kve_protection ) {
151             retMaps[i].prems |= PREMS_WRITE;
152         }
153
154         if( KVME_PROT_EXEC & maps[i].kve_protection ) {
155             retMaps[i].prems |= PREMS_EXEC;
156         }
157
158         strncpy(retMaps[i].path, maps[i].kve_path, VM_PATH_MAX-1);
159         retMaps[i].path[VM_PATH_MAX-1] = '\0';
160     }
161
162     free(maps);
163     return retMaps;
164 }
165
166 int sysctl_computeAddrWidth(pid_t /*pid*/) {
167     int retSize = sizeof(void *);
168
169 #if defined(arch_64bit)
170     const int X86_ADDR_WIDTH = 4;
171
172     size_t length;
173     struct kinfo_proc *procInfo = getProcInfo(pid, length, false);
174     if( NULL == procInfo ) {
175         fprintf(stderr, "Failed to determine address width of process %d\n", pid);
176         return -1;
177     }
178
179     if( std::string(procInfo->ki_emul).find("ELF32") != std::string::npos ) {
180         retSize = X86_ADDR_WIDTH;
181     }
182     free(procInfo);
183 #endif
184
185     return retSize;
186 }
187
188 bool sysctl_findProcLWPs(pid_t pid, std::vector<pid_t> &lwps) {
189     size_t length;
190     struct kinfo_proc *procInfo = getProcInfo(pid, length, true);
191     if( NULL == procInfo ) {
192         fprintf(stderr, "Failed to determine LWP ids for process %d\n", pid);
193         return false;
194     }
195
196
197     int numEntries = length / procInfo->ki_structsize;
198     for(int i = 0; i < numEntries; ++i) {
199         lwps.push_back(procInfo[i].ki_tid);
200     }
201     free(procInfo);
202
203     return true;
204 }
205
206 static bool PtraceBulkAccess(Dyninst::Address inTraced, unsigned size, void *inSelf, int pid, bool read) {
207     struct ptrace_io_desc io;
208
209     io.piod_op = (read ? PIOD_READ_D : PIOD_WRITE_D);
210     io.piod_addr = inSelf;
211     io.piod_offs = (void *)inTraced;
212     io.piod_len = size;
213
214     unsigned amountRead = 0;
215
216     while( amountRead < size ) {
217         io.piod_len -= amountRead;
218         io.piod_addr = ((unsigned char *)io.piod_addr) + amountRead;
219         io.piod_offs = ((unsigned char *)io.piod_offs) + amountRead;
220
221         if( 0 != ptrace(PT_IO, pid, (caddr_t)&io, 0) ) return false;
222         amountRead += io.piod_len;
223     }
224
225     return true;
226 }
227
228 bool PtraceBulkRead(Dyninst::Address inTraced, unsigned size, void *inSelf, int pid) {
229     return PtraceBulkAccess(inTraced, size, inSelf, pid, true);
230 }
231
232 bool PtraceBulkWrite(Dyninst::Address inTraced, unsigned size, void *inSelf, int pid) {
233     return PtraceBulkAccess(inTraced, size, inSelf, pid, false);
234 }