+static char *
+escape_path (char *name)
+{
+ if (strchr (name, '\\')) {
+ char *s = g_malloc (strlen (name) * 2);
+ int len, i, j;
+
+ len = strlen (name);
+ j = 0;
+ for (i = 0; i < len; ++i) {
+ if (name [i] == '\\') {
+ s [j ++] = '\\';
+ s [j ++] = '\\';
+ } else {
+ s [j ++] = name [i];
+ }
+ }
+ return s;
+ }
+ return name;
+}
+
+static void
+emit_all_line_number_info (MonoDwarfWriter *w)
+{
+ int i;
+ GHashTable *dir_to_index, *index_to_dir;
+ GSList *l;
+ GSList *info_list;
+
+ g_assert (w->collect_line_info);
+
+ add_line_number_file_name (w, "<unknown>", 0, 0);
+
+ /* Collect files */
+ info_list = g_slist_reverse (w->line_info);
+ for (l = info_list; l; l = l->next) {
+ MethodLineNumberInfo *info = l->data;
+ MonoDebugMethodInfo *minfo;
+ char *source_file;
+ GPtrArray *source_file_list;
+
+ // FIXME: Free stuff
+ minfo = mono_debug_lookup_method (info->method);
+ if (!minfo)
+ continue;
+
+ mono_debug_symfile_get_line_numbers_full (minfo, &source_file, &source_file_list, NULL, NULL, NULL, NULL, NULL);
+ for (i = 0; i < source_file_list->len; ++i) {
+ MonoDebugSourceInfo *sinfo = g_ptr_array_index (source_file_list, i);
+ add_line_number_file_name (w, sinfo->source_file, 0, 0);
+ }
+ }
+
+ /* Preprocess files */
+ dir_to_index = g_hash_table_new (g_str_hash, g_str_equal);
+ index_to_dir = g_hash_table_new (NULL, NULL);
+ for (i = 0; i < w->line_number_file_index; ++i) {
+ char *name = g_hash_table_lookup (w->index_to_file, GUINT_TO_POINTER (i + 1));
+ char *copy;
+ int dir_index = 0;
+
+ if (g_path_is_absolute (name)) {
+ char *dir = g_path_get_dirname (name);
+
+ dir_index = GPOINTER_TO_UINT (g_hash_table_lookup (dir_to_index, dir));
+ if (dir_index == 0) {
+ dir_index = w->line_number_dir_index;
+ w->line_number_dir_index ++;
+ copy = g_strdup (dir);
+ g_hash_table_insert (dir_to_index, copy, GUINT_TO_POINTER (dir_index + 1));
+ g_hash_table_insert (index_to_dir, GUINT_TO_POINTER (dir_index + 1), copy);
+ } else {
+ dir_index --;
+ }
+
+ g_free (dir);
+ }
+ }
+
+ /* Line number info header */
+ emit_section_change (w, ".debug_line", 0);
+ emit_label (w, ".Ldebug_line_section_start");
+ emit_label (w, ".Ldebug_line_start");
+ emit_symbol_diff (w, ".Ldebug_line_end", ".", -4); /* length */
+ emit_int16 (w, 0x2); /* version */
+ emit_symbol_diff (w, ".Ldebug_line_header_end", ".", -4); /* header_length */
+ emit_byte (w, 1); /* minimum_instruction_length */
+ emit_byte (w, 1); /* default_is_stmt */
+ emit_byte (w, LINE_BASE); /* line_base */
+ emit_byte (w, LINE_RANGE); /* line_range */
+ emit_byte (w, OPCODE_BASE); /* opcode_base */
+ emit_byte (w, 0); /* standard_opcode_lengths */
+ emit_byte (w, 1);
+ emit_byte (w, 1);
+ emit_byte (w, 1);
+ emit_byte (w, 1);
+ emit_byte (w, 0);
+ emit_byte (w, 0);
+ emit_byte (w, 0);
+ emit_byte (w, 1);
+ emit_byte (w, 0);
+ emit_byte (w, 0);
+ emit_byte (w, 1);
+
+ /* Includes */
+ emit_section_change (w, ".debug_line", 0);
+ for (i = 0; i < w->line_number_dir_index; ++i) {
+ char *dir = g_hash_table_lookup (index_to_dir, GUINT_TO_POINTER (i + 1));
+
+ emit_string (w, escape_path (dir));
+ }
+ /* End of Includes */
+ emit_byte (w, 0);
+
+ /* Files */
+ for (i = 0; i < w->line_number_file_index; ++i) {
+ char *name = g_hash_table_lookup (w->index_to_file, GUINT_TO_POINTER (i + 1));
+ char *basename = NULL, *dir;
+ int dir_index = 0;
+
+ if (g_path_is_absolute (name)) {
+ dir = g_path_get_dirname (name);
+
+ dir_index = GPOINTER_TO_UINT (g_hash_table_lookup (dir_to_index, dir));
+ basename = g_path_get_basename (name);
+ }
+
+ if (basename)
+ emit_string (w, basename);
+ else
+ emit_string (w, escape_path (name));
+ emit_uleb128 (w, dir_index);
+ emit_byte (w, 0);
+ emit_byte (w, 0);
+ }
+
+ /* End of Files */
+ emit_byte (w, 0);
+
+ emit_label (w, ".Ldebug_line_header_end");
+
+ /* Emit line number table */
+ for (l = info_list; l; l = l->next) {
+ MethodLineNumberInfo *info = l->data;
+
+ emit_line_number_info (w, info->method, info->start_symbol, info->end_symbol, info->code, info->code_size, info->debug_info);
+ }
+ g_slist_free (info_list);
+
+ emit_byte (w, 0);
+ emit_byte (w, 1);
+ emit_byte (w, DW_LNE_end_sequence);
+
+ emit_label (w, ".Ldebug_line_end");
+}
+