[ipc/ipcdev.git] / qnx / src / ipc3x_dev / ti / syslink / procMgr / hlos / knl / loaders / Elf / Qnx / DLOAD / DLWRAPPER / dlw_debug.c
1 /*
2 * dlw_debug.c
3 *
4 * This source file contains the implementation of the DLL debug support.
5 * The client side of the ELF dynamic loader will write to target memory a
6 * list of module debug records containing the final addresses of all
7 * segments that were loaded to target memory by the dynamic loader.
8 *
9 * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/
10 *
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 *
16 * Redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer.
18 *
19 * Redistributions in binary form must reproduce the above copyright
20 * notice, this list of conditions and the following disclaimer in the
21 * documentation and/or other materials provided with the
22 * distribution.
23 *
24 * Neither the name of Texas Instruments Incorporated nor the names of
25 * its contributors may be used to endorse or promote products derived
26 * from this software without specific prior written permission.
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
31 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
32 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
33 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
34 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
35 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
36 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
37 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
38 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39 *
40 */
42 #include "ArrayList.h"
43 #include "symtab.h"
44 #include "dload.h"
45 #include "dload_api.h"
46 #include "util.h"
47 #include "dlw_debug.h"
49 /*****************************************************************************/
50 /* dl_debug */
51 /* */
52 /* Define a LIFO linked list "class" of DL_Module_Debug_Record pointers. */
53 /*****************************************************************************/
54 TYPE_STACK_IMPLEMENTATION(DL_Host_Module_Debug*, dl_debug)
56 /*****************************************************************************/
57 /* mirror_debug_ptr */
58 /* */
59 /* Define a linked list "class" of DL_Host_Module_Debug pointers. */
60 /*****************************************************************************/
61 TYPE_QUEUE_IMPLEMENTATION(DL_Host_Module_Debug*, mirror_debug_ptr)
63 /*---------------------------------------------------------------------------*/
64 /* DLL debug support is enabled if _DLModules symbol is found in base image. */
65 /*---------------------------------------------------------------------------*/
66 BOOL DLL_debug = FALSE;
67 mirror_debug_ptr_Queue mirror_debug_list;
68 dl_debug_Stack dl_debug_stk;
69 TARGET_ADDRESS DLModules_loc = 0;
71 /*---------------------------------------------------------------------------*/
72 /* Global flag to control debug output. */
73 /*---------------------------------------------------------------------------*/
74 #if LOADER_DEBUG
75 extern int debugging_on;
76 #endif
78 /*---------------------------------------------------------------------------*/
79 /* Global flag to enable profiling. */
80 /*---------------------------------------------------------------------------*/
81 #if LOADER_DEBUG || LOADER_PROFILE
82 extern int profiling_on;
83 #endif
85 /*****************************************************************************/
86 /* DLDBG_ADD_HOST_RECORD() - Construct a host version of a debug record */
87 /* that is to be associated with the specified module. The debug */
88 /* record is placed on the top of the "context stack" while the module */
89 /* is being loaded so that debug information about the location of the */
90 /* module segments can be added during the load. */
91 /*****************************************************************************/
92 void DLDBG_add_host_record(const char *module_name)
93 {
94 /*------------------------------------------------------------------------*/
95 /* Allocate a new DL_Host_Module_Debug record from host memory. */
96 /*------------------------------------------------------------------------*/
97 DL_Host_Module_Debug *host_dbg =
98 (DL_Host_Module_Debug *)malloc(sizeof(DL_Host_Module_Debug));
100 /*------------------------------------------------------------------------*/
101 /* Set up initial values. Make a copy of the module name; everything */
102 /* else is NULL. */
103 /*------------------------------------------------------------------------*/
104 host_dbg->module_name = (char *)malloc(strlen(module_name) + 1);
105 strncpy(host_dbg->module_name, module_name, strlen(module_name));
106 host_dbg->module_name[strlen(module_name)] = '\0';
108 host_dbg->num_segments = 0;
109 host_dbg->segment_list_head =
110 host_dbg->segment_list_tail = NULL;
112 /*------------------------------------------------------------------------*/
113 /* Push the new host version of the debug record onto the context stack. */
114 /* This module is now currently being loaded. When its segments are */
115 /* allocated and written into target memory, the debug record at the top */
116 /* of the context stack will get updated with new segment information. */
117 /*------------------------------------------------------------------------*/
118 dl_debug_push(&dl_debug_stk, host_dbg);
119 }
121 /*****************************************************************************/
122 /* DLDBG_ADD_TARGET_RECORD() - Host version of the debug record on the top */
123 /* of the context stack is now complete and the module associated has */
124 /* been successfully loaded. It is now time to create a target version */
125 /* of the debug record based on the host version. Allocate space for */
126 /* the target record and write the information from the host version of */
127 /* record into the target memory. The host will retain a mirror copy */
128 /* of the target debug record list so that it can update pointers in */
129 /* the list when debug records are added to or removed from the list. */
130 /*****************************************************************************/
131 void DLDBG_add_target_record(int handle)
132 {
133 int i;
134 DL_Host_Module_Debug *host_dbg = dl_debug_pop(&dl_debug_stk);
135 struct DLOAD_MEMORY_REQUEST targ_req;
136 struct DLOAD_MEMORY_SEGMENT obj_desc;
137 DL_Host_Segment *host_seg = NULL;
138 DL_Target_Module_Debug *targ_dbg = NULL;
139 char *targ_module_name = NULL;
141 /*------------------------------------------------------------------------*/
142 /* Assign handle after loading has been completed. */
143 /*------------------------------------------------------------------------*/
144 host_dbg->handle = handle;
146 /*------------------------------------------------------------------------*/
147 /* Figure out how much target memory we need to hold all of the debug */
148 /* record information for the module that just finished loading and its */
149 /* segments. */
150 /*------------------------------------------------------------------------*/
151 obj_desc.memsz_in_bytes = sizeof(DL_Target_Module_Debug) +
152 (sizeof(DL_Target_Segment) * (host_dbg->num_segments - 1)) +
153 (strlen(host_dbg->module_name) + 1);
156 /*------------------------------------------------------------------------*/
157 /* Build up request for target memory in a local data object. */
158 /*------------------------------------------------------------------------*/
159 targ_req.fp = NULL;
160 targ_req.align = 4;
161 targ_req.flags |= DLOAD_SF_relocatable;
163 /*------------------------------------------------------------------------*/
164 /* Request the target memory for the new debug record. */
165 /*------------------------------------------------------------------------*/
166 if (!DLTMM_malloc(&targ_req, &obj_desc))
167 {
168 DLIF_error(DLET_MEMORY,
169 "Failed to allocate target memory for debug record.\n");
170 exit(1);
171 }
173 /*------------------------------------------------------------------------*/
174 /* Write content of host version of the debug record into the target */
175 /* version of the debug record in target memory. */
176 /*------------------------------------------------------------------------*/
177 targ_dbg = (DL_Target_Module_Debug *)obj_desc.target_address;
178 targ_dbg->tool_version = INIT_VERSION;
179 targ_dbg->verification_word = VERIFICATION;
180 targ_dbg->num_segments = host_dbg->num_segments;
182 for (host_seg = host_dbg->segment_list_head, i = 0;
183 host_seg; host_seg = host_seg->next_segment, i++)
184 {
185 targ_dbg->segments[i].load_address = host_seg->load_address;
186 targ_dbg->segments[i].run_address = host_seg->run_address;
187 }
189 if (i != host_dbg->num_segments)
190 {
191 DLIF_error(DLET_MISC, "Debug record segment list mismatch.\n");
192 exit(1);
193 }
195 targ_module_name = ((char *)obj_desc.target_address +
196 sizeof(DL_Target_Module_Debug) +
197 (sizeof(DL_Target_Segment) * (host_dbg->num_segments - 1)));
199 memcpy(targ_module_name, host_dbg->module_name,
200 strlen(host_dbg->module_name) + 1);
202 /*------------------------------------------------------------------------*/
203 /* The host will hold onto access info for all target debug records so */
204 /* the debug record list can be properly managed when adding or removing */
205 /* debug records to/from the list. */
206 /*------------------------------------------------------------------------*/
207 host_dbg->target_address = obj_desc.target_address;
208 host_dbg->next_module_ptr = NULL;
209 host_dbg->next_module_size = 0;
211 /*------------------------------------------------------------------------*/
212 /* Link the new target debug record into the module debug list. This */
213 /* means updating the debug record currently at the end of the list to */
214 /* point at and give the size of the new debug record. */
215 /*------------------------------------------------------------------------*/
216 if (mirror_debug_list.size == 0)
217 {
218 DL_Debug_List_Header *dbg_hdr = (DL_Debug_List_Header *)DLModules_loc;
219 dbg_hdr->first_module_ptr = (uint32_t)(obj_desc.target_address);
220 dbg_hdr->first_module_size = obj_desc.memsz_in_bytes;
221 }
222 else
223 {
224 DL_Host_Module_Debug *tail_host_dbg = mirror_debug_list.back_ptr->value;
225 DL_Target_Module_Debug *tail_targ_dbg = tail_host_dbg->target_address;
227 tail_targ_dbg->next_module_ptr =
228 tail_host_dbg->next_module_ptr = (uint32_t)(obj_desc.target_address);
229 tail_targ_dbg->next_module_size =
230 tail_host_dbg->next_module_size = obj_desc.memsz_in_bytes;
231 }
233 mirror_debug_ptr_enqueue(&mirror_debug_list, host_dbg);
235 #if LOADER_DEBUG
236 if (debugging_on) DLDBG_dump_mirror_debug_list();
237 #endif
238 }
240 /*****************************************************************************/
241 /* DLDBG_RM_TARGET_RECORD() - Find the host version of the module debug */
242 /* record on the mirror DLL debug list so that we can then find the */
243 /* target version of the module debug record. We'll unlink the target */
244 /* version of the record from the DLL debug list, free the target */
245 /* memory associated with the debug record, then finally, free the */
246 /* host version of the module debug record. */
247 /*****************************************************************************/
248 void DLDBG_rm_target_record(int handle)
249 {
250 mirror_debug_ptr_Queue_Node *prev_itr = NULL;
251 mirror_debug_ptr_Queue_Node *itr = mirror_debug_list.front_ptr;
252 DL_Host_Module_Debug *prev_host_dbg = NULL;
253 DL_Host_Module_Debug *host_dbg = itr->value;
255 /*------------------------------------------------------------------------*/
256 /* Base Image is assumed to have handle ID == 1, it won't be on the */
257 /* DLL Debug list, so don't bother looking for it. */
258 /*------------------------------------------------------------------------*/
259 if (handle <= 1) return;
261 /*------------------------------------------------------------------------*/
262 /* Find host version of the module debug record using the module handle. */
263 /*------------------------------------------------------------------------*/
264 for (; itr; itr = itr->next_ptr)
265 {
266 host_dbg = itr->value;
267 if (host_dbg->handle == handle) break;
268 prev_itr = itr;
269 }
271 if (!itr)
272 {
273 printf("Couldn't find handle %d on debug list\n", handle);
274 return;
275 }
277 /*------------------------------------------------------------------------*/
278 /* Unlink the target version of the module debug record from the DLL */
279 /* debug list in target memory. */
280 /*------------------------------------------------------------------------*/
281 /* The debug record to be removed may be in the middle or at the end of */
282 /* the DLL debug list, or ... */
283 /*------------------------------------------------------------------------*/
284 if (prev_itr)
285 {
286 DL_Target_Module_Debug *prev_targ_dbg = NULL;
288 prev_host_dbg = prev_itr->value;
289 prev_targ_dbg = (DL_Target_Module_Debug *)prev_host_dbg->target_address;
291 prev_host_dbg->next_module_ptr =
292 prev_targ_dbg->next_module_ptr = host_dbg->next_module_ptr;
293 prev_host_dbg->next_module_size =
294 prev_targ_dbg->next_module_size = host_dbg->next_module_size;
295 }
297 /*------------------------------------------------------------------------*/
298 /* The debug record could be at the front of the DLL debug list. If so, */
299 /* then we'll need to update the content of the list header object. */
300 /*------------------------------------------------------------------------*/
301 else
302 {
303 DL_Debug_List_Header *dbg_hdr = (DL_Debug_List_Header *)DLModules_loc;
304 dbg_hdr->first_module_ptr = host_dbg->next_module_ptr;
305 dbg_hdr->first_module_size = host_dbg->next_module_size;
306 }
308 /*------------------------------------------------------------------------*/
309 /* Free target memory associated with the target version of the module */
310 /* debug record. */
311 /*------------------------------------------------------------------------*/
312 DLTMM_free((char *)host_dbg->target_address);
314 /*------------------------------------------------------------------------*/
315 /* Find and remove the host version of the module debug record from the */
316 /* mirror version of the DLL debug list, then free the host memory */
317 /* associated with the object. */
318 /*------------------------------------------------------------------------*/
319 mirror_debug_ptr_remove(&mirror_debug_list, host_dbg);
321 #if LOADER_DEBUG
322 if (debugging_on) DLDBG_dump_mirror_debug_list();
323 #endif
324 }
326 /*****************************************************************************/
327 /* DLDBG_ADD_SEGMENT_RECORD() - Add a new segment record for the debug */
328 /* record for the module at the top of the context stack. */
329 /*****************************************************************************/
330 void DLDBG_add_segment_record(struct DLOAD_MEMORY_SEGMENT *obj_desc)
331 {
332 /*------------------------------------------------------------------------*/
333 /* Get access to the module debug record at the top of the context stack. */
334 /*------------------------------------------------------------------------*/
335 DL_Host_Module_Debug *host_dbg = dl_debug_stk.top_ptr->value;
337 /*------------------------------------------------------------------------*/
338 /* Allocate host memory for a new segment debug record. */
339 /*------------------------------------------------------------------------*/
340 DL_Host_Segment *host_seg = (DL_Host_Segment *)malloc(sizeof(DL_Host_Segment));
342 /*------------------------------------------------------------------------*/
343 /* Fill load and run address fields of new segment debug record. */
344 /*------------------------------------------------------------------------*/
345 host_seg->load_address =
346 host_seg->run_address = (uint32_t)obj_desc->target_address;
347 host_seg->next_segment = NULL;
349 /*------------------------------------------------------------------------*/
350 /* Add the new segment debug record to the end of the segment list that */
351 /* is attached to the module debug record. */
352 /*------------------------------------------------------------------------*/
353 if (host_dbg->num_segments == 0)
354 {
355 host_dbg->segment_list_head =
356 host_dbg->segment_list_tail = host_seg;
357 }
358 else
359 {
360 host_dbg->segment_list_tail->next_segment = host_seg;
361 host_dbg->segment_list_tail = host_seg;
362 }
364 host_dbg->num_segments++;
365 }
367 /*****************************************************************************/
368 /* DLDBG_DUMP_MIRROR_DEBUG_LIST() - Write out contents of mirror debug list */
369 /* so that we can debug what is being written to target memory on */
370 /* behalf of the DLL View support. */
371 /*****************************************************************************/
372 void DLDBG_dump_mirror_debug_list(void)
373 {
374 mirror_debug_ptr_Queue_Node *itr = mirror_debug_list.front_ptr;
376 DL_Debug_List_Header *dbg_hdr = (DL_Debug_List_Header *)DLModules_loc;
377 printf("DLL View Debug List Header at 0x%lx\n", (unsigned long)dbg_hdr);
378 printf(" first module debug record at: 0x%lx\n",
379 (unsigned long)dbg_hdr->first_module_ptr);
380 printf(" first module debug record size: %d\n",
381 (int)dbg_hdr->first_module_size);
383 while (itr)
384 {
385 int i;
386 DL_Host_Module_Debug *host_dbg = itr->value;
387 DL_Host_Segment *host_seg = NULL;
389 printf("Module Debug Record for %s at 0x%lx\n",
390 host_dbg->module_name, (unsigned long)host_dbg->target_address);
391 printf(" next module debug record at: 0x%lx\n",
392 (unsigned long)host_dbg->next_module_ptr);
393 printf(" next module debug record size: %d\n",
394 (int)host_dbg->next_module_size);
396 printf(" handle for %s is %d\n", host_dbg->module_name, host_dbg->handle);
397 printf(" segment list for %s:\n", host_dbg->module_name);
398 for (i = 0, host_seg = host_dbg->segment_list_head;
399 host_seg; i++, host_seg = host_seg->next_segment)
400 {
401 printf(" segment [%d] load address: 0x%lx\n",
402 i, (unsigned long)host_seg->load_address);
403 printf(" segment [%d] run address: 0x%lx\n",
404 i, (unsigned long)host_seg->run_address);
405 }
407 itr = itr->next_ptr;
408 }
409 }