xref: /reactos/dll/win32/dbghelp/rsym.c (revision c8d07514)
1 /*
2  * PROJECT:         ReactOS dbghelp extension
3  * LICENSE:         GPLv2+ - See COPYING in the top level directory
4  * PURPOSE:         Parse rsym information for use with dbghelp
5  * PROGRAMMER:      Mark Jansen
6  */
7 
8 #include "dbghelp_private.h"
9 #include <reactos/rossym.h>
10 
11 #include <wine/debug.h>
12 WINE_DEFAULT_DEBUG_CHANNEL(dbghelp_rsym);
13 
14 
15 typedef struct rsym_file_entry_s
16 {
17     const char* File;
18     unsigned Source;
19 } rsym_file_entry_t;
20 
21 typedef struct rsym_func_entry_s
22 {
23     ULONG_PTR Address;
24     struct symt_function* func;
25     struct rsym_func_entry_s* next;
26 } rsym_func_entry_t;
27 
28 
29 
30 /******************************************************************
31  *		rsym_finalize_function (copied from stabs_finalize_function)
32  *
33  * Ends function creation: mainly:
34  * - cleans up line number information
35  * - tries to set up a debug-start tag (FIXME: heuristic to be enhanced)
36  */
37 static void rsym_finalize_function(struct module* module, struct symt_function* func)
38 {
39     IMAGEHLP_LINE64     il;
40     struct location     loc;
41 
42     if (!func) return;
43     symt_normalize_function(module, func);
44     /* To define the debug-start of the function, we use the second line number.
45      * Not 100% bullet proof, but better than nothing
46      */
47     if (symt_fill_func_line_info(module, func, func->address, &il) &&
48         symt_get_func_line_next(module, &il))
49     {
50         loc.kind = loc_absolute;
51         loc.offset = il.Address - func->address;
52         symt_add_function_point(module, func, SymTagFuncDebugStart,
53                                 &loc, NULL);
54     }
55 }
56 
57 
58 static int is_metadata_sym(const char* name)
59 {
60     ULONG len = name ? strlen(name) : 0;
61     return len > 3 && name[0] == '_' && name[1] != '_' && name[len-1] == '_' && name[len-2] == '_';
62 };
63 
64 static int use_raw_address(const char* name)
65 {
66     if (!name)
67         return 0;
68 
69     if (!strcmp(name, "__ImageBase"))
70         return 1;
71 
72     if (!strcmp(name, "__RUNTIME_PSEUDO_RELOC_LIST__"))
73         return 1;
74 
75     return 0;
76 }
77 
78 
79 BOOL rsym_parse(struct module* module, unsigned long load_offset,
80                  const void* rsym_ptr, int rsymlen)
81 {
82     const ROSSYM_HEADER* RosSymHeader;
83     const ROSSYM_ENTRY* First, *Last, *Entry;
84     const CHAR* Strings;
85 
86     struct pool pool;
87     struct sparse_array file_table, func_table;
88     rsym_func_entry_t* first_func = NULL;
89 
90 
91     RosSymHeader = rsym_ptr;
92 
93     if (RosSymHeader->SymbolsOffset < sizeof(ROSSYM_HEADER)
94         || RosSymHeader->StringsOffset < RosSymHeader->SymbolsOffset + RosSymHeader->SymbolsLength
95         || rsymlen < RosSymHeader->StringsOffset + RosSymHeader->StringsLength
96         || 0 != (RosSymHeader->SymbolsLength % sizeof(ROSSYM_ENTRY)))
97     {
98         WARN("Invalid ROSSYM_HEADER\n");
99         return FALSE;
100     }
101 
102     First = (const ROSSYM_ENTRY *)((const char*)rsym_ptr + RosSymHeader->SymbolsOffset);
103     Last = First + RosSymHeader->SymbolsLength / sizeof(ROSSYM_ENTRY);
104     Strings = (const CHAR*)rsym_ptr + RosSymHeader->StringsOffset;
105 
106     pool_init(&pool, 65536);
107     sparse_array_init(&file_table, sizeof(rsym_file_entry_t), 64);
108     sparse_array_init(&func_table, sizeof(rsym_func_entry_t), 128);
109 
110     for (Entry = First; Entry != Last; Entry++)
111     {
112         ULONG Address = load_offset + Entry->Address;
113         if (!Entry->FileOffset)
114         {
115             rsym_func_entry_t* func = sparse_array_find(&func_table, Entry->FunctionOffset);
116 
117             /* We do not want to define a data point where there is already a function! */
118             if (!func || func->Address != Address)
119             {
120                 const char* SymbolName = Strings + Entry->FunctionOffset;
121                 if (!is_metadata_sym(SymbolName))
122                 {
123                     /* TODO: How should we determine the size? */
124                     ULONG Size = sizeof(ULONG);
125                     if (use_raw_address(SymbolName))
126                         Address = Entry->Address;
127 
128                     symt_new_public(module, NULL, SymbolName, FALSE, Address, Size);
129                 }
130                 else
131                 {
132                     /* Maybe use it to fill some metadata? */
133                 }
134             }
135         }
136         else
137         {
138             rsym_file_entry_t* file = sparse_array_find(&file_table, Entry->FileOffset);
139             rsym_func_entry_t* func = sparse_array_find(&func_table, Entry->FunctionOffset);
140 
141             if (!file)
142             {
143                 file = sparse_array_add(&file_table, Entry->FileOffset, &pool);
144                 file->File = Strings + Entry->FileOffset;
145                 file->Source = source_new(module, NULL, Strings + Entry->FileOffset);
146             }
147 
148             if (!func)
149             {
150                 func = sparse_array_add(&func_table, Entry->FunctionOffset, &pool);
151                 func->func = symt_new_function(module, NULL, Strings + Entry->FunctionOffset,
152                     Address, 0, NULL);
153                 func->Address = Address;
154                 func->next = first_func;
155                 first_func = func;
156             }
157 
158             /* TODO: What if we have multiple chunks scattered around? */
159             symt_add_func_line(module, func->func, file->Source, Entry->SourceLine, Address - func->Address);
160         }
161     }
162 
163     while (first_func)
164     {
165         /* TODO: Size of function? */
166         rsym_finalize_function(module, first_func->func);
167         first_func = first_func->next;
168     }
169 
170     module->module.SymType = SymDia;
171     module->module.CVSig = 'R' | ('S' << 8) | ('Y' << 16) | ('M' << 24);
172     module->module.LineNumbers = TRUE;
173     module->module.GlobalSymbols = TRUE;
174     module->module.TypeInfo = FALSE;
175     module->module.SourceIndexed = TRUE;
176     module->module.Publics = TRUE;
177 
178     pool_destroy(&pool);
179 
180     return TRUE;
181 }
182 
183