diff options
| author | Po Lu | 2023-08-07 08:51:11 +0800 |
|---|---|---|
| committer | Po Lu | 2023-08-07 08:51:11 +0800 |
| commit | c71a520d1da636a722cf87b46534ca3b5aafbc7b (patch) | |
| tree | 95a3099c065800f60602e0a403b551a6d6dba139 /exec/exec.c | |
| parent | 18e7bc87521e3c48b819cfe4a113f532ba905561 (diff) | |
| parent | 9a9f73041d09d2da7ed562c7ffae0d9519562fba (diff) | |
| download | emacs-c71a520d1da636a722cf87b46534ca3b5aafbc7b.tar.gz emacs-c71a520d1da636a722cf87b46534ca3b5aafbc7b.zip | |
Introduce an Android window system port for GNU Emacs
* src/xterm.h: New fields `quit_keysym' and `quit_keysym_time'.
* src/xterm.c (handle_one_xevent): Check for the quit keysym, and
set Vquit_flag upon witnessing two clicks in rapid succession.
(x_term_init): Set `quit_keysym'.
(init_xterm): Fix typo in name of `register_textconv_interface'.
(syms_of_xterm) <Vx_toolkit_scroll_bars>: Describe its default
value on android.
* src/xfns.c (xic_string_conversion_callback): Pass `0' as the
last argument to textconv_query.
(Fx_server_vendor, Fx_server_version): Document return values on
Android.
* src/xfaces.c (Fx_family_fonts, set_lface_from_font): Use
FRAME_RES instead of FRAME_RES_Y, respecting user preferences on
window systems that have distinct display and font scaling
factors.
(Fx_load_color_file): Call `emacs_fclose', not fclose.
* src/xdisp.c (tab_bar_item_info): Allow `close_p' to be NULL.
(get_tab_bar_item): Update commentary to reflect that change.
(get_tab_bar_item_kbd): New function, resembling get_tab_bar_item.
(build_desired_tool_bar_string): Clear `f->tool_bar_wraps_p';
insert new line characters if a QCwrap item is encountered, and
set f->tool_bar_wrap_p. Replace characters beyond the end of the
tool bar with spaces.
(display_tool_bar_line): Move iterator to the next line if in
contact with an explicit line-wrap item.
(redisplay_internal): If there are newline characters in the tool
bar, refrain from coercing each row into being identically tall.
Don't call `set_tty_color_mode' on Android.
(mark_window_display_accurate_1): Report changes to the point and
mark to input methods.
(display_menu_bar): Adjust ifdefs to allow non-X window systems to
use the built-in menu bar.
(draw_row_with_mouse_face): Don't call TTY functions on Android.
(note_mouse_highlight): Call `popup_activated' on Android.
(expose_frame): Correctly work on the menu bar window.
(gui_union_rectangles): New function.
* src/window.h (struct window): New fields for recording the last
window and point positions, along with an ephemeral position used
during IM text conversion.
(WINDOW_MENU_BAR_P): Correct definition for non-X window systems
without external menu bars.
* src/window.c (replace_buffer_in_windows): Call
Qreplace_buffer_in_windows only when bound.
* src/w32proc.c (sys_spawnve): Pass extra argument to openp.
* src/w32font.c (fill_in_logfont): Use font scaling factor, not
the display scaling factor.
* src/w32.c (check_windows_init_file): Pass extra argument to
openp.
* src/verbose.mk.in (AM_V_JAVAC, AM_V_DX, AM_V_AAPT)
(AM_V_ZIPALIGN, AM_V_SILENT): New variables.
* src/textconv.h (struct textconv_interface): New `point_changed',
`compose_region_changed' and `notify_conversion'.
Add declarations for new functions.
* src/textconv.c (TEXTCONV_DEBUG): New macro.
(suppress_conversion_count): New variable.
(enum textconv_batch_edit_flags): New flag.
(copy_buffer): Don't overwrite text before the gap with the text
after.
(get_mark, select_window): New functions.
(textconv_query): New argument FLAGS. Contingent upon its value,
use the previous point or mark or skip the conversion region.
(sync_overlay, record_buffer_change, reset_frame_state)
(detect_conversion_events, restore_selected_window)
(really_commit_text, really_finish_composing_text)
(really_set_composing_region, really_delete_composing_text)
(really_request_point_update, really_set_point_and_mark)
(complete_edit): New functions.
(struct complete_edit_check_context): New structure; store in it
the result of editing operations.
(complete_edit_check, handle_pending_conversion_events_1)
(decrement_inside, handle_pending_conversion_events)
(start_batch_edit, end_batch_edit, commit_text)
(set_composing_text, textconv_set_point_and_mark)
(request_point_update, textconv_barrier, get_extracted_text)
(get_surrounding_text, conversion_disabled_p)
(report_selected_window_change, report_point_change)
(disable_text_conversion, resume_text_conversion)
(register_textconv_interface, check_postponed_buffers)
(postponed_buffers, Fset_text_conversion_style)
(syms_of_textconv) <Qaction, Qtext_conversion, Qpush_mark,
Qunderline, Qoverriding_text_conversion_style,
Vtext_conversion_edits, Voverriding_text_conversion_style,
Vtext_conversion_face>: New functions, symbols and variables.
* src/terminal.c (Fterminal_live_p): Return Qandroid if type is
output_android.
* src/termhooks.h (enum output_method): Add `output_android'.
(struct terminal) <display_info>: Add union constituent field for
`android'.
<query_colors>: Define on Android as well.
(TERMINAL_FONT_CACHE) [HAVE_ANDROID]: Return the inappropriately
named font cache field on Android.
* src/term.c (string_cost, string_cost_one_line, per_line_cost)
(calculate_costs, produce_glyphs, produce_glyphs, tty_capable_p)
(tty_capable_p, device, init_tty, maybe_fatal)
(delete_tty) [HAVE_ANDROID]: Exclude or turn these functions into
vestiges.
(Fsuspend_tty, Fresume_tty): Call `emacs_fclose' and always signal
on Android.
(Fresume_tty): Call `emacs_fdopen'.
(Ftty__set_output_buffer_size) [HAVE_ANDROID]: Remove this
function.
(encode_terminal_code): Replace with a stub.
(init_tty, delete_tty, maybe_fatal): Call `emacs_fclose'.
(syms_of_term): Remove most unnecessary code on Android.
<system_uses_terminfo>: Always set this option on Android.
* src/sysdep.c (init_standard_fds): Call emacs_fopen.
(reset_sigio, widen_foreground_group): Define out on Android.
(reset_sys_modes): Don't call either function on Android.
(init_sigbus, handle_sigbus): New functions.
(init_signals): Don't add user signals on Android. Register
signal handlers for SIGBUS, and refrain from handling SIGSEGV.
(emacs_fstatat): Wrap android_fstatat on Android.
(sys_fstat, sys_faccessat): New function.
(emacs_openat): Exclude this function when building libemacs.so.
(emacs_open, emacs_open_noquit, emacs_fopen, emacs_close): Wrap
functions defined in the Android filesystem emulation code.
(emacs_fdopen, emacs_fclose, emacs_unlink, emacs_symlink)
(emacs_rmdir, emacs_mkdir, emacs_renameat_noreplace, emacs_rename)
(emacs_fchmodat): New wrappers for more of those functions.
(close_output_streams): Placate the file descriptor sanitizer
that's included with android.
* src/sound.c (Fplay_sound_internal): Pass extra argument to openp.
* src/sfntfont.h:
* src/sfntfont.c:
* src/sfntfont-android.c:
* src/sfnt.h:
* src/sfnt.c: New files.
* src/scroll.c: Exclude the entire file on Android.
* src/process.c: (allocate_pty): Call sys_faccessat, not
faccessat.
(Fmake_process): Call openp with an extra argument.
(wait_reading_process_output): Call android_select.
(Fprocess_send_eof): Don't call tcdrain if not present.
(handle_child_signal): Write a comment describing a small, seldom
encountered issue.
* src/print.c (print_vectorlike): Don't print FONT_EXTRA_INDEX for
font entities.
* src/pdumper.c (Fdump_emacs_portable): Allow dumping in
interactive Emacs's on Android, as this is performed within
loadup.el.
(dump_discard_mem): Use madvise if posix_advise is not present.
(pdumper_load): Call sys_fstat, not fstat.
(syms_of_pdumper) <Vpdumper_fingerprint>: Calculate the
fingerprint for this Emacs executable and store it there.
* src/menu.c (have_boxes): Android has boxes.
(push_submenu_start, push_submenu_end): Define on Android.
(single_menu_item): Produce submenus on Android as well.
(x_popup_menu_1): Call EVENT_START, in contrast to duplicating its
old functionality with calls to Fcar and XCDR.
(Fx_popup_menu): Update documentation to reflect that touch screen
events are now accepted as POSITION.
* src/marker.c (set_marker_internal): Redisplay buffers when their
mark changes, enabling changes to be reported to the IME.
* src/lread.c (lread_fd, lread_fd_cmp, lread_fd_p, lread_close)
(lread_fstat, lread_read_quit, lread_lseek, file_stream)
(file_seek, file_stream_valid_p, file_stream_close)
(file_stream_invalid, getc): New macros. Define to an
implementation with file descriptors and file streams on systems
other than Android 2.3+, and one using Android file descriptors on
those systems.
(USE_ANDROID_ASSETS): Define on Android 2.3+;
(file_get_char): New function.
(infile, skip_dyn_bytes, skip_dyn_eof, readbyte_from_stdio)
(read_filtered_event, safe_to_load_version, close_infile_unwind):
Implement in terms of those macros.
(close_file_unwind_android_fd): New function.
(Fload): Pass extra argument to `openp' and use Android file
descriptors where possible.
(Flocate_file_internal): Pass extra argument to `openp'.
(maybe_swap_for_eln1): Call sys_fstat, not fstat.
(openp): New arg PLATFORM; if supplied and opening a
platform-specific file descriptor replacement is possible, place
one there.
(build_load_history): Fix typos in comments.
(skip_lazy_string): Implement in terms of the aformentioned
macros.
* src/lisp.h: Add declarations for new functions.
* src/keyboard.h (reading_key_sequence): Declare here.
(EVENT_START): Treat touch screen events specially by returning
the posn of their touch point.
* src/keyboard.c (reading_key_sequence, menu_bar_touch_id): New
variables.
(command_loop_1):
(read_menu_command): Pass false to read_key_sequence.
(read_char): Update commentary.
(readable_events): If text conversion events (edits from an input
method) are queued, return 1.
(kbd_buffer_get_event): If text conversion events exist, carry out
the edits contained within. Then, generate a Qtext_conversion
event.
(lispy_function_keys, FUNCTION_KEY_OFFSET): Define function key
array on Android.
(coords_in_tab_bar_window): New function.
(make_lispy_event) <TOUCHSCREEN_BEGIN_EVENT>: Keep track of
touches that fall into the confines of the tab bar, and include
the tab bar item in their position lists. Moreover, retain and
track the touch in C code if it's taking place within the menu
bar.
<TOUCHSCREEN_END_EVENT>: Likewise for the tab bar; generate menu
bar events if the touch ends on a menu item and was previously
singled out for tracking.
<TOUCHSCREEN_UPDATE_EVENT>: Don't deliver this event if the frame
is dead, or if it was identified for tracking since the only touch
sequence that changed begun inside the menu bar.
(handle_async_input): Call android_check_query_urgent.
(handle_input_available_signal): Add memory fence.
(parse_tool_bar_item): Handle `wrap' properties within tool bar
items moving subsequent items onto a new row.
(access_keymap_keyremap): New arguments START, END, KEYBUF.
Set Qcurrent_key_remap_sequence around calls to the remap
function.
(keyremap_step): Pass the necessary information to
access_keymap_keyremap.
(restore_reading_key_sequence): New function.
(read_key_sequence): Set `reading_key_sequence'. New arg
DISABLE_TEXT_CONVERSION_P, which causes text conversion to be
disabled as long as the key sequence is being read. Disable text
conversion as well if a menu or function key prefix is read,
insert imaginary prefix keys before touchscreen events within
special areas of a frame. Don't insert prefix keys if input is
being mocked, which transpires if the input is in actuality
originating from a key translation map.
(read_key_sequence_vs): New argument DISABLE_TEXT_CONVERSION.
(Fread_key_sequence): New argument DISABLE_TEXT_CONVERSION.
(Fopen_dribble_file): Use emacs_fclose.
(head_table): Make touchscreen-begin and touchscreen-end events
touchscreen events.
(syms_of_keyboard) <QCwrap, Qtouchscreen, Qtext_conversion>: New
symbols.
<disable_inhibit_text_conversion, Vcurrent_key_remap_sequence>:
New variables.
* src/inotify.c (Finotify_add_watch): Detect and avoid watching
special files that don't exist from the POV of inotify.
* src/image.c (image_create_bitmap_from_data)
(image_create_bitmap_from_file, free_bitmap_record)
(prepare_image_for_display, image_clear_image_1)
(image_clear_image_1, image_size_in_bytes, image_set_transform):
(Create_Pixmap_From_Bitmap_Data, lookup_rgb_color)
(image_to_emacs_colors, image_from_emacs_colors)
(image_pixmap_draw_cross, image_disable_image): Implement on
Android, reusing much of the X11 code.
(matrix_identity, matrix_rotate, matrix_mirror_horizontal)
(matrix_translate): New functions.
(x_check_image_size, x_create_x_image_and_pixmap)
(x_destroy_x_image, image_check_image_size)
(image_create_x_image_and_pixmap_1, image_destroy_x_image)
(gui_put_x_image, image_get_x_image, image_unget_x_image):
Implement on Android.
(image_find_image_fd): Return an Android file descriptor if
possible.
(close_android_fd): New function.
(slurp_file): Accept `image_fds', defined to Android file
descriptors.
(xpm_load): Enable built-in XPM support on Android.
(xbm_load, pbm_load, png_load_body, jpeg_load_body, gif_load)
(webp_load, imagemagick_load_image, svg_load): Use image file
descriptors on Android; these file descriptors may in fact
represent compressed asset streams, and obviate the necessity of
creating a new file descriptor for each asset image opened.
(Fimage_transforms_p): Report rotate90 on Android.
(image_types, syms_of_image): Enable built-in XPM support on
Android.
* src/fringe.c (init_fringe_bitmap): Bit swap bitmaps on Android,
as on X.
* src/frame.h (enum text_conversion_operation): New enumerator.
(struct text_conversion_action, struct text_conversion_state): New
variable.
(struct frame): New fields `tool_bar_wraps_p' and `conversion'.
Increase the width of `output_method'.
<output_data>: Add `android' field.
<wait_event_type>: Define on Android as well.
(fset_menu_bar_window): Define correctly, so that it's declared on
non-X builds without external menu bars.
(FRAME_ANDROID_P): Define macro.
(FRAME_WINDOW_P) [HAVE_ANDROID]: Define to FRAME_ANDROID_P.
(FRAME_RES): New macro.
(MOUSE_HL_INFO): Define without referencing tty output data on
Android, which doesn't have them.
* src/frame.c (Fframep): Return `android' on Android systems.
(Fwindow_system): Likewise.
(make_frame): Clear text conversion state and `tool_bar_wraps_p'.
(Fmake_terminal_frame): Signal that Android doesn't support text
terminals.
(delete_frame): Reset text conversion state prior to deleting the
frame.
(gui_display_get_resource): Don't call the resource hook on
Android.
(Fx_parse_geometry): Pacify compiler warning.
(make_monitor_attribute_list): Don't always use SOURCE if nil.
(syms_of_frame) <Qandroid>: New symbol.
<Vdefault_frame_scroll_bars>: Don't default scroll bars to an
enabled state on Android.
* src/fontset.c (fontset_find_font): Tackle an unusual problem.
* src/font.h (struct font_entity): New field `is_android'.
(PT_PER_INCH): Define to 160.00 on Android.
* src/font.c (font_make_entity): New function.
(font_make_entity_android): New variant that sets `is_android' to
true.
(font_pixel_size, font_find_for_lface, font_open_for_lface)
(Ffont_face_attributes, Fopen_font): Respect the distinction
between frame text and display scales.
* src/fns.c (Flocale_info): Silence compiler warning.
* src/filelock.c (BOOT_TIME): Undefine BOOT_TIME when building
libemacs.so
(get_boot_time, rename_lock_file, create_lock_file)
(current_lock_owner, make_lock_file_name, unlock_file): Employ
wrappers for Android filesystem operations.
* src/fileio.c (emacs_fd, emacs_fd_open, emacs_fd_close)
(emacs_fd_read, emacs_fd_lseek, emacs_fd_fstat, emacs_fd_valid_p):
New type and macros; define them to suitable values, akin to those
in lread.c
(check_vfs_filename): New function.
(file_access_p): Call `sys_faccessat'.
(close_file_unwind_emacs_fd): New function.
(fclose_unwind): Call `emacs_fclose', not fclose.
(file_name_directory): Export this function.
(user_homedir): If PW->pw_dir is not set and its uid is the
current user, call `android_get_home_directory'.
(get_homedir): Call `android_get_home_directory' if PW->pw_dir is
not set.
(Fcopy_file, Fmake_directory_internal, Fdelete_directory_internal)
(Fdelete_file, Frename_file, Fmake_symbolic_link, Faccess_file)
(file_directory_p, file_accessible_directory_p, Fset_file_modes)
(Fset_file_times, Ffile_newer_than_file_p, read_non_regular)
(Finsert_file_contents, write_region)
(Fverify_visited_file_modtime, Fset_visited_file_modtime)
(do_auto_save_unwind): Make use of Android filesystem wrappers and
file descriptors where possible.
(Fadd_name_to_file): Prohibit creating links to and from files
residing on Android special directories.
(Ffile_system_info): Avoid compilation failure on Android, where
Gnulib can't find out how to implement statfs.
* src/epaths.in [HAVE_ANDROID && !ANDROID_STUBIFY]: Deface this
file, so Makefile cannot change the hard-coded values within.
* src/emacs.c (using_utf8): Correctly initialize mbstate_t on
Android.
(init_cmdargs): Pass extra argument to openp.
(load_pdump): When building libemacs.so, use solely the file
provided on the command line or as an argument to
`android_emacs_init'.
(load_seccomp): Call sys_fstat, not fstat.
(main, android_emacs_init): Name `main' `android_emacs_init' when
building libemacs.so, and accept an argument designating the dump
file.
(main): Initialize text conversion and Android. Don't presume
that argv is NULL terminated.
(Fkill_emacs, shut_down_emacs): Properly implement RESTART on
Android.
(syms_of_emacs) <Vsystem_type>: Describe the possible value
`android'.
* src/emacs-module.c (MODULE_HANDLE_NONLOCAL_EXIT): Cease relying
on GCC clean-up attribute extension.
(MODULE_INTERNAL_CLEANUP): New macro.
(module_make_global_ref, module_free_global_ref)
(module_make_function, module_get_function_finalizer)
(module_make_interactive, module_funcall, module_extract_integer)
(module_extract_float, module_copy_string_contents)
(module_get_user_ptr, module_set_user_ptr)
(module_get_user_finalizer, module_set_user_finalizer)
(module_vec_set, module_vec_size, module_process_input)
(module_extract_big_integer, module_make_big_integer): Carry out
necessary clean-up tasks using MODULE_HANDLE_NONLOCAL_EXIT.
* src/editfns.c (Fuser_full_name): Call `android_user_full_name',
as USER_FULL_NAME doesn't always work.
* src/doc.c (doc_fd, doc_fd_p, doc_open, doc_read_quit)
(doc_lseek): New types and macros, resembling those in lread.c.
(get_doc_string, Fsnarf_documentation): Implement in terms of
those macros, so as to use Android asset streams directly.
* src/dispnew.c (clear_current_matrices, clear_desired_matrices)
(allocate_matrices_for_window_redisplay, free_glyphs)
(redraw_frame, update_frame, scrolling, update_frame_line):
Disable support for text terminals when building for Android.
(Fopen_termscript): Use emacs_fclose.
(init_display_interactive): Set Vinitial_window_system to
Qandroid, and lose if Emacs needs to create a text terminal.
* src/dispextern.h (No_Cursor, Emacs_Rectangle, struct gui_box):
New definitions.
(struct glyph_string) <gc>: Define to the Android GC type.
(HAVE_NATIVE_TRANSPHORMS): Define on Android.
(struct image): New fields `ximg', `mask_img', as on X.
(enum tool_bar_item_idx): New tool bar item property
TOOL_BAR_ITEM_WRAP.
* src/dired.c (emacs_dir, emacs_closedir, emacs_readdir): New
typedef and definitions.
(open_directory): Return emacs_dir; use android_opendir on
Android, instead of at-funcs.
(directory_files_internal_unwind): Call emacs_closedir.
(read_dirent): Call emacs_readdir.
(directory_files_internal, file_name_completion)
(file_name_completion_dirp): Use Android wrappers for directories
and files.
(file_attributes): Abstain from openat on Android.
* src/conf_post.h (MB_CUR_MAX): Define to REPLACEMENT_MB_CUR_MAX
if necessary to counteract inept LLVM headers.
* src/coding.h (from_unicode_buffer): Define if HAVE_ANDROID as
well.
* src/coding.c (from_unicode_buffer): Define on Android, creating
a variant that understands UCS-16 extended into wchar_t.
(syms_of_coding) <Qutf_16le>: Define on Android.
* src/charset.c (load_charset_map_from_file): Supply extra
argument to openp, and call Emacs wrappers for fdopen and fclose.
* src/callproc.c (get_current_directory): Return the home
directory if ENCODED is a special directory.
(delete_temp_file): Call emacs_unlink in lieu of unlink.
(call_process): Use openp.
(emacs_spawn): Use Android executable loader binary if needed and
enabled.
(init_callproc): Set Vshell_file_name to /system/bin/sh if
libemacs.so.
(syms_of_callproc) <Vctags_program_name, Vetags_program_name,
Vhexl_program_name, Vemacsclient_program_name,
Vmovemail_program_name>: New variables. Define to the names of
the programs they respectively stand for.
* src/callint.c (Fcall_interactively): Supply new argument in
calls to Fread_key_sequence and Fread_key_sequence_vector.
* src/buffer.h (struct buffer) <text_conversion_style_>: New bvar.
(bset_text_conversion_style): New bvar setter.
* src/buffer.c (init_buffer_once): Set the text conversion style.
(syms_of_buffer) <BVAR (current_buffer, text_conversion_style)>:
Define new BLV.
* src/androidvfs.c:
* src/androidterm.h:
* src/androidterm.c:
* src/androidselect.c:
* src/androidmenu.c:
* src/androidgui.h:
* src/androidfont.c:
* src/androidfns.c:
* src/android.h:
* src/android.c:
* src/android-emacs.c:
* src/android-asset.h: New function.
* src/alloc.c (cleanup_vector): Finalize Android font entities.
(find_string_data_in_pure) [__i386__ && !__clang__]: On Android,
compensate for a bug in the latest NDK GCC.
(mark_pinned_symbols, android_make_lisp_symbol): Elude another
bug in debuginfo generation with an almost nonsensical fix.
(garbage_collect): Mark androidterm and sfntfont.
(mark_frame): Mark text conversion actions and info.
* src/Makefile.in (XCONFIGURE): New variable. If set, add srcdir
to vpath.
(hostlib): New variable, always defined to libgnu.a on the build
machine.
(GIF_CFLAGS, JPEG_CFLAGS, TIFF_CFLAGS, SQLITE3_CFLAGS)
(LIBSELINUX_CFLAGS, ANDROID_OBJ, ANDROID_LIBS, ANDROID_LDFLAGS)
(ANDROID_BUILD_CFLAGS, LIBGMP_CFLAGS): New variables.
(CM_OBJ): Update commentary.
(EMACS_CFLAGS): Add new compiler flags variables.
(base_obj): Add ANDROID_OBJ.
(SOME_MACHINE_OBJECTS): Add Android-related objects.
(lisp.mk): Generate from its absolute file name.
($(lispsource)/international/charprop.el): Don't generate when
building libemacs.so.
($(libsrc)/make-docfile$(EXEEXT)
$(libsrc)/make-fingerprint$(EXEEXT)): Depend on libgnu.a on the
build machine.
(mostlyclean): Remove libemacs.so.
(build-counter.c, libemacs.so, android-emacs): New targets. These
targets are made from this Makefile copied to a subdirectory of
`cross', and provide the Emacs library and an ancillary binary
used by the Android port.
* nt/mingw-cfg.site:
* nt/gnulib-cfg.mk: Impede building Gnulib's vasnprintf* code.
* msdos/sedlibmk.inp:
* msdos/sedlibcf.inp:
* msdos/sed3v2.inp:
* msdos/sed1v2.inp: Fix the DJGPP build.
* make-dist (possibly_non_vc_files): Add exec/configure and
exec/config.h.in.
* m4/ndk-build.m4: New file.
* m4/getline.m4:
* m4/getdelim.m4:
* m4/asm-underscore.m4: Update from Gnulib.
* lisp/wid-edit.el (widget-event-point): Treat touch screen events
correctly.
(widget-keymap): Map touchscreen-begin to widget-button-click.
(widget-event-start): New function.
(widget-button--check-and-call-button):
(widget-button-click): Behave correctly when confronted by touch
screen events.
* lisp/version.el (android-read-build-system)
(android_read_build_time): New functions.
(emacs-build-system, emacs-repository-version-android)
(emacs-repository-get-version):
(emacs-repository-get-branch): Implement properly on Android, by
reading a file generated during the packaging process.
* lisp/touch-screen.el: New file, supplying support for
translating raw touch screen events into gestures.
* lisp/tool-bar.el (secondary-tool-bar-map): New defvar.
(tool-bar--cache-key, tool-bar--secondary-cache-key): Make
defsubsts.
(tool-bar--flush-key): Flush caches for the secondary tool bar as
well.
(tool-bar-make-keymap, tool-bar-make-keymap-1): Append the
secondary tool bar map below the primary tool bar map.
(modifier-bar-modifier-list): New variable.
(tool-bar-apply-modifiers, modifier-bar-button)
(tool-bar-event-apply-alt-modifier)
(tool-bar-event-apply-super-modifier)
(tool-bar-event-apply-hyper-modifier)
(tool-bar-event-apply-shift-modifier)
(tool-bar-event-apply-control-modifier)
(tool-bar-event-apply-meta-modifier, modifier-bar-available-p)
(modifier-bar-mode): New functions.
* lisp/textmodes/text-mode.el (text-mode): Set
text-conversion-style to t.
* lisp/textmodes/reftex-global.el (reftex-create-tags-file): Use
etags-program-name to provide the name of the etags program.
* lisp/textmodes/conf-mode.el (conf-mode-initialize): Enable text
conversion.
* lisp/textmodes/artist.el (artist-figlet-get-font-list): Use
/system/bin/sh on Android.
* lisp/term/android-win.el: New file.
* lisp/term.el (term-mode): Always display the on screen keyboard.
(term-exec-1): Use /system/bin/sh on Android.
* lisp/tab-line.el (tab-line-tab-map)
(tab-line-new-tab)
(tab-line-select-tab)
(tab-line-close-tab)
(tab-line-track-tap)
(tab-line-event-start): Improve support for touch screen events.
* lisp/tab-bar.el (tab-bar-mouse-context-menu):
(tab-bar-map): Likewise.
(tab-bar-handle-timeout, tab-bar-touchscreen-begin): New
functions.
* lisp/subr.el (event-start): Don't return nonsense if EVENT is a
touchscreen event.
(event-end): Likewise.
(read-key): Disable text conversion within
read-key-sequence-vector.
(read-char-choice-with-read-key): Display the on screen keyboard.
(read-char-from-minibuffer): Disable text conversion.
(use-dialog-box-p): Prefer dialog boxes on Android.
(y-or-n-p): Disable text conversion properly under all three modes
of operation.
* lisp/startup.el (android-fonts-enumerated): New variable.
(normal-top-level): Load system fonts on Android.
* lisp/speedbar.el (speedbar-fetch-etags-command): Use
etags-program-name instead of hard-coding `etags'.
* lisp/simple.el (normal-erase-is-backspace-setup-frame): Return
true on Android.
(event-apply-modifier): Correctly apply Shift and Control
modifiers to keys with other modifiers.
(undo-auto-amalgamate): Mention analyze-text-conversion wrt being
an amalgamating command.
* lisp/shell.el (shell--command-completion-data): Don't lose
if PATH contains an inaccessible directory.
* lisp/progmodes/prog-mode.el (prog-mode): Enable text conversion.
* lisp/progmodes/cperl-mode.el (cperl-etags): Don't hard-code
etags, employ etags-program-name instead.
* lisp/progmodes/cc-mode.el (c-initialize-cc-mode): Initialize
text conversion hook.
* lisp/progmodes/cc-cmds.el (c-post-text-conversion): New
function. Do electric characters.
* lisp/play/gamegrid.el (gamegrid-setup-default-font): Don't crash
if the display resolution is too high.
* lisp/play/dunnet.el (text-conversion-style):
* lisp/play/doctor.el (doctor-mode): Enable text conversion.
* lisp/pixel-scroll.el (pixel-scroll-precision-scroll-down-page)
(pixel-scroll-precision-scroll-Up-page): Make autoloads.
* lisp/org/org-ctags.el (org-ctags-path-to-ctags): Use
ctags-program-name, not ctags.
* lisp/obsolete/terminal.el (terminal-emulator): Start
/system/bin/sh, not /bin/sh.
* lisp/net/tramp.el (tramp-encoding-shell): Use /system/bin/sh on
Android.
* lisp/net/eww.el (eww-form-submit, eww-form-file)
(eww-form-checkbox, eww-form-select): Define these faces on
Android as well.
* lisp/net/browse-url.el (browse-url-default-browser)
(browse-url--browser-defcustom-type): Specify on Android.
(browse-url-android-share, browse-url-default-android-browser):
New option and function.
* lisp/mwheel.el (mouse-wheel-down-event, mouse-wheel-up-event)
(mouse-wheel-left-event, mouse-wheel-right-event): Define suitably
on Android.
* lisp/mouse.el (minor-mode-menu-from-indicator): New argument
EVENT. Use it for positioning the menu.
(mouse-minor-mode-menu): Pass EVENT to that function.
* lisp/minibuffer.el (clear-minibuffer-message): Don't clear the
message if `touch-screen-preview-select' may be underway.
(minibuffer-mode): Enable text conversion.
(minibuffer-setup-on-screen-keyboard)
(minibuffer-exit-on-screen-keyboard): New functions.
* lisp/menu-bar.el (menu-bar-close-window): New option.
(menu-bar-edit-menu): Bind execute-extended-command to a menu
item.
(kill-this-buffer, kill-this-buffer-enabled-p): Respect
menu-bar-close-window.
* lisp/mail/rmail.el (rmail-autodetect, rmail-insert-inbox-text):
Don't hard-code the name of movemail; rather, use
movemail-program-name.
* lisp/mail/emacsbug.el (emacs-build-description): Insert the
Android version and manufacturer.
* lisp/ls-lisp.el (ls-lisp-use-insert-directory-program): Default
to off on Android.
* lisp/loadup.el: Set load-list to empty load list after startup;
dump the first time Emacs starts, and load Android related
miscellanea.
* lisp/isearch.el (isearch-text-conversion-style): New variable.
(isearch-mode, isearch-done): Display the OSK, then temporarily
disable and restore the on screen keyboard.
* lisp/international/mule-cmds.el (set-coding-system-map): Update
menu definition for Android.
* lisp/international/fontset.el (script-representative-chars)
(setup-default-fontset): Improve detection of CJK fonts.
* lisp/image/wallpaper.el: Fix compiler warning.
* lisp/ielm.el (inferior-emacs-lisp-mode): Don't hard-code name of
hexl, replacing that with hexl-program-name.
* lisp/htmlfontify.el (hfy-etags-bin): Replace hard-coded Emacs
with etags-program-name.
* lisp/hexl.el (hexl-program): Replace hard-coded hexl.
* lisp/help-macro.el (make-help-screen): Display the on screen
keyboard and disable text conversion prior to reading options.
* lisp/gnus/mail-source.el (mail-source-movemail-program): Replace
hard-coded movemail with movemail-program-name.
* lisp/gnus/gnus-score.el (gnus-read-char): New function.
(gnus-summary-increase-score): Use a dialog box to display
these options on Android.
* lisp/frame.el (frame-geometry, frame-edges)
(mouse-absolute-pixel-position, set-mouse-absolute-pixel-position)
(frame-list-z-order, frame-restack, display-mouse-p)
(display-popup-menus-p, display-graphic-p, display-symbol-keys-p)
(display-screens, display-pixel-height, display-pixel-width)
(display-mm-height, display-mm-width, display-backing-store)
(display-save-under, display-planes, display-color-cells)
(display-visual-class, display-monitor-attributes-list): Implement
window system specific functions on Android.
* lisp/files.el (basic-save-buffer): Allow files to exist without
a parent directory.
* lisp/faces.el (tool-bar): Use default definition on Android.
* lisp/emacs-lisp/eldoc.el (eldoc-add-command-completions): Add
touch-screen-handle-touch and analyze-text-conversion.
* lisp/elec-pair.el (electric-pair-analyze-conversion): New
function.
* lisp/doc-view.el (doc-view-menu): Improve menu.
(doc-view-tool-bar-map): Add a new tool bar for Doc View.
(doc-view-new-search): New command.
(doc-view-mode): Enable that new tool bar.
* lisp/dired-aux.el (dired-do-chxxx, dired-do-chmod)
(dired-do-print, dired-do-shell-command, dired-do-compress-to)
(dired-do-create-files, dired-do-rename, dired-do-isearch)
(dired-do-isearch-regexp, dired-do-search)
(dired-do-query-replace-regexp, dired-do-find-regexp)
(dired-vc-next-action): Disable ``click to select'' after
running this command.
* lisp/dired.el (dired-insert-set-properties): Attach
click-to-select keymap to file names if necessary.
(dired-mode-map): Bind `touchscreen-hold' to click to select
mode.
(dired-post-do-command): New function.
(dired-do-delete): Call it.
(dired-mark-for-click, dired-enable-click-to-select-mode): New
functions.
(dired-click-to-select-mode): New minor mode.
* lisp/cus-edit.el (custom-button-mouse, custom-button-pressed)
(custom-display): Define faces to their default values on Android.
* lisp/comint.el (comint-mode): Enable text conversion.
* lisp/cedet/semantic/db-ebrowse.el
(semanticdb-create-ebrowse-database): Replace fixed ebrowse with
ebrowse-program-name.
* lisp/calc/calc.el (calc-mode): Display the on screen keyboard.
(calc): Insist on displaying the on screen keyboard.
* lisp/button.el (button-map): Bind touch screen events to
push-button.
(push-button): Deal with touch screen events.
* lisp/bindings.el (cut, paste, cut, text-conversion): New
bindings.
* lisp/battery.el (battery-status-function): Use
`battery-android'.
(battery-android): New function.
* lib/gnulib.mk.in:
* lib/getline.c:
* lib/getdelim.c:
* lib/Makefile.in: Update from Gnulib.
* lib-src/emacsclient.c (decode_options): Set `alt_display' to
`android'.
* lib-src/asset-directory-tool.c: New file.
* lib-src/Makefile.in: Adapt for cross-compilation.
* java/res/xml/preferences.xml:
* java/res/values/style.xml:
* java/res/values/strings.xml:
* java/res/values/bool.xml:
* java/res/values-v29/style.xml:
* java/res/values-v24/bool.xml:
* java/res/values-v19/bool.xml:
* java/res/values-v14/style.xml:
* java/res/values-v11/style.xml:
* java/org/gnu/emacs/EmacsWindowAttachmentManager.java:
* java/org/gnu/emacs/EmacsWindow.java:
* java/org/gnu/emacs/EmacsView.java:
* java/org/gnu/emacs/EmacsThread.java:
* java/org/gnu/emacs/EmacsSurfaceView.java:
* java/org/gnu/emacs/EmacsService.java:
* java/org/gnu/emacs/EmacsSdk8Clipboard.java:
* java/org/gnu/emacs/EmacsSdk7FontDriver.java:
* java/org/gnu/emacs/EmacsSdk23FontDriver.java:
* java/org/gnu/emacs/EmacsSdk11Clipboard.java:
* java/org/gnu/emacs/EmacsSafThread.java:
* java/org/gnu/emacs/EmacsPreferencesActivity.java:
* java/org/gnu/emacs/EmacsPixmap.java:
* java/org/gnu/emacs/EmacsOpenActivity.java:
* java/org/gnu/emacs/EmacsNoninteractive.java:
* java/org/gnu/emacs/EmacsNative.java:
* java/org/gnu/emacs/EmacsMultitaskActivity.java:
* java/org/gnu/emacs/EmacsLauncherPreferencesActivity.java:
* java/org/gnu/emacs/EmacsInputConnection.java:
* java/org/gnu/emacs/EmacsHolder.java:
* java/org/gnu/emacs/EmacsHandleObject.java:
* java/org/gnu/emacs/EmacsGC.java:
* java/org/gnu/emacs/EmacsFontDriver.java:
* java/org/gnu/emacs/EmacsFillRectangle.java:
* java/org/gnu/emacs/EmacsFillPolygon.java:
* java/org/gnu/emacs/EmacsDrawable.java:
* java/org/gnu/emacs/EmacsDrawRectangle.java:
* java/org/gnu/emacs/EmacsDrawPoint.java:
* java/org/gnu/emacs/EmacsDrawLine.java:
* java/org/gnu/emacs/EmacsDocumentsProvider.java:
* java/org/gnu/emacs/EmacsDirectoryEntry.java:
* java/org/gnu/emacs/EmacsDialogButtonLayout.java:
* java/org/gnu/emacs/EmacsDialog.java:
* java/org/gnu/emacs/EmacsCursor.java:
* java/org/gnu/emacs/EmacsContextMenu.java:
* java/org/gnu/emacs/EmacsClipboard.java:
* java/org/gnu/emacs/EmacsApplication.java:
* java/org/gnu/emacs/EmacsActivity.java:
* java/debug.sh:
* java/README:
* java/Makefile.in:
* java/INSTALL:
* java/AndroidManifest.xml.in:
* exec/trace.c:
* exec/test.c:
* exec/mipsfpu.h:
* exec/mipsfpu.c:
* exec/mipsel-user.h:
* exec/loader-x86_64.s:
* exec/loader-x86.s:
* exec/loader-mipsel.s:
* exec/loader-mips64el.s:
* exec/loader-armeabi.s:
* exec/loader-aarch64.s:
* exec/install-sh:
* exec/exec1.c:
* exec/exec.h:
* exec/exec.c:
* exec/deps.mk:
* exec/configure.ac:
* exec/config.sub:
* exec/config.h.in:
* exec/config.guess:
* exec/config-mips.m4.in:
* exec/README:
* exec/Makefile.in:
* etc/images/last-page.xpm: New files.
* etc/PROBLEMS: Expound upon problems with font instructing on
Android.
* etc/NEWS: Announce changes.
* etc/MACHINES: Describe support for Android.
* etc/DEBUG: Illustrate the steps to debug Emacs on Android.
* doc/lispref/processes.texi (Subprocess Creation):
* doc/lispref/os.texi (System Environment):
* doc/lispref/keymaps.texi (Translation Keymaps):
(Extended Menu Items):
(Tool Bar):
* doc/lispref/frames.texi (Frames):
(Frame Layout):
(Font and Color Parameters):
(Pop-Up Menus):
(Window System Selections):
* doc/lispref/elisp.texi (Top):
* doc/lispref/display.texi (Defining Faces):
(Window Systems):
* doc/lispref/commands.texi (Touchscreen Events):
(Touchscreen Events):
(Misc Events):
(Key Sequence Input):
* doc/emacs/windows.texi (Tab Line):
* doc/emacs/input.texi:
* doc/emacs/frames.texi (Tool Bars):
(Tab Bars):
* doc/emacs/emacs.texi (Top):
* doc/emacs/dired.texi (Marks vs Flags):
* doc/emacs/android.texi:
* doc/emacs/Makefile.in (EMACSSOURCES): Update the documentation
to properly describe changes effected.
* cross/verbose.mk.android:
* cross/ndk-build/ndk-resolve.mk:
* cross/ndk-build/ndk-prebuilt-static-library.mk:
* cross/ndk-build/ndk-prebuilt-shared-library.mk:
* cross/ndk-build/ndk-clear-vars.mk:
* cross/ndk-build/ndk-build.mk.in:
* cross/ndk-build/ndk-build-static-library.mk:
* cross/ndk-build/ndk-build-shared-library.mk:
* cross/ndk-build/ndk-build-executable.mk:
* cross/ndk-build/README:
* cross/ndk-build/Makefile.in:
* cross/langinfo.h:
* cross/README:
* cross/Makefile.in: New files.
* configure.ac: Configure Emacs for cross-compilation on Android.
* build-aux/ndk-module-extract.awk:
* build-aux/ndk-build-helper.mk:
* build-aux/ndk-build-helper-4.mk:
* build-aux/ndk-build-helper-3.mk:
* build-aux/ndk-build-helper-2.mk:
* build-aux/ndk-build-helper-1.mk:
* build-aux/makecounter.sh: New file.
* autogen.sh: Autogen in exec as well.
* admin/merge-gnulib (GNULIB_MODULES): Add getline, stpncpy and
strnlen. Clean lib.
* README:
* Makefile.in:
* INSTALL: Update for Android.
* .dir-locals.el (c-mode): Add a few new types.
Diffstat (limited to 'exec/exec.c')
| -rw-r--r-- | exec/exec.c | 1235 |
1 files changed, 1235 insertions, 0 deletions
diff --git a/exec/exec.c b/exec/exec.c new file mode 100644 index 00000000000..0d9187cabfa --- /dev/null +++ b/exec/exec.c | |||
| @@ -0,0 +1,1235 @@ | |||
| 1 | /* Program execution for Emacs. | ||
| 2 | |||
| 3 | Copyright (C) 2023 Free Software Foundation, Inc. | ||
| 4 | |||
| 5 | This file is part of GNU Emacs. | ||
| 6 | |||
| 7 | GNU Emacs is free software: you can redistribute it and/or modify | ||
| 8 | it under the terms of the GNU General Public License as published by | ||
| 9 | the Free Software Foundation, either version 3 of the License, or (at | ||
| 10 | your option) any later version. | ||
| 11 | |||
| 12 | GNU Emacs is distributed in the hope that it will be useful, | ||
| 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | GNU General Public License for more details. | ||
| 16 | |||
| 17 | You should have received a copy of the GNU General Public License | ||
| 18 | along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ | ||
| 19 | |||
| 20 | #include <config.h> | ||
| 21 | |||
| 22 | #include <errno.h> | ||
| 23 | #include <unistd.h> | ||
| 24 | #include <fcntl.h> | ||
| 25 | #include <assert.h> | ||
| 26 | #include <string.h> | ||
| 27 | #include <ctype.h> | ||
| 28 | #include <stdlib.h> | ||
| 29 | |||
| 30 | #include <sys/ptrace.h> | ||
| 31 | #include <sys/param.h> | ||
| 32 | #include <sys/mman.h> | ||
| 33 | |||
| 34 | #include "exec.h" | ||
| 35 | |||
| 36 | #if defined __mips__ && !defined MIPS_NABI | ||
| 37 | #include "mipsfpu.h" | ||
| 38 | #endif /* defined __mips__ && !defined MIPS_NABI */ | ||
| 39 | |||
| 40 | |||
| 41 | |||
| 42 | |||
| 43 | /* Define replacements for required string functions. */ | ||
| 44 | |||
| 45 | #if !defined HAVE_STPCPY || !defined HAVE_DECL_STPCPY | ||
| 46 | |||
| 47 | /* Copy SRC to DEST, returning the address of the terminating '\0' in | ||
| 48 | DEST. */ | ||
| 49 | |||
| 50 | static char * | ||
| 51 | rpl_stpcpy (char *dest, const char *src) | ||
| 52 | { | ||
| 53 | register char *d; | ||
| 54 | register const char *s; | ||
| 55 | |||
| 56 | d = dest; | ||
| 57 | s = src; | ||
| 58 | |||
| 59 | do | ||
| 60 | *d++ = *s; | ||
| 61 | while (*s++ != '\0'); | ||
| 62 | |||
| 63 | return d - 1; | ||
| 64 | } | ||
| 65 | |||
| 66 | #define stpcpy rpl_stpcpy | ||
| 67 | #endif /* !defined HAVE_STPCPY || !defined HAVE_DECL_STPCPY */ | ||
| 68 | |||
| 69 | #if !defined HAVE_STPNCPY || !defined HAVE_DECL_STPNCPY | ||
| 70 | |||
| 71 | /* Copy no more than N bytes of SRC to DST, returning a pointer past | ||
| 72 | the last non-NUL byte written into DST. */ | ||
| 73 | |||
| 74 | static char * | ||
| 75 | rpl_stpncpy (char *dest, const char *src, size_t n) | ||
| 76 | { | ||
| 77 | char c, *s; | ||
| 78 | size_t n4; | ||
| 79 | |||
| 80 | s = dest; | ||
| 81 | |||
| 82 | if (n >= 4) | ||
| 83 | { | ||
| 84 | n4 = n >> 2; | ||
| 85 | |||
| 86 | for (;;) | ||
| 87 | { | ||
| 88 | c = *src++; | ||
| 89 | *dest++ = c; | ||
| 90 | if (c == '\0') | ||
| 91 | break; | ||
| 92 | c = *src++; | ||
| 93 | *dest++ = c; | ||
| 94 | if (c == '\0') | ||
| 95 | break; | ||
| 96 | c = *src++; | ||
| 97 | *dest++ = c; | ||
| 98 | if (c == '\0') | ||
| 99 | break; | ||
| 100 | c = *src++; | ||
| 101 | *dest++ = c; | ||
| 102 | if (c == '\0') | ||
| 103 | break; | ||
| 104 | if (--n4 == 0) | ||
| 105 | goto last_chars; | ||
| 106 | } | ||
| 107 | n -= dest - s; | ||
| 108 | goto zero_fill; | ||
| 109 | } | ||
| 110 | |||
| 111 | last_chars: | ||
| 112 | n &= 3; | ||
| 113 | if (n == 0) | ||
| 114 | return dest; | ||
| 115 | |||
| 116 | for (;;) | ||
| 117 | { | ||
| 118 | c = *src++; | ||
| 119 | --n; | ||
| 120 | *dest++ = c; | ||
| 121 | if (c == '\0') | ||
| 122 | break; | ||
| 123 | if (n == 0) | ||
| 124 | return dest; | ||
| 125 | } | ||
| 126 | |||
| 127 | zero_fill: | ||
| 128 | while (n-- > 0) | ||
| 129 | dest[n] = '\0'; | ||
| 130 | |||
| 131 | return dest - 1; | ||
| 132 | } | ||
| 133 | |||
| 134 | #define stpncpy rpl_stpncpy | ||
| 135 | #endif /* !defined HAVE_STPNCPY || !defined HAVE_DECL_STPNCPY */ | ||
| 136 | |||
| 137 | |||
| 138 | |||
| 139 | /* Executable reading functions. | ||
| 140 | These functions extract information from an executable that is | ||
| 141 | about to be loaded. | ||
| 142 | |||
| 143 | `exec_0' takes the name of the program, determines whether or not | ||
| 144 | its format is correct, and if so, returns the list of actions that | ||
| 145 | the loader should perform. | ||
| 146 | |||
| 147 | The actions include: | ||
| 148 | |||
| 149 | - Making the stack executable, if PT_GNU_STACK. | ||
| 150 | - Mapping PT_LOAD sections into the executable with the correct | ||
| 151 | memory protection. | ||
| 152 | - On MIPS, setting the floating point register size. | ||
| 153 | - Transferring control to the interpreter or executable. */ | ||
| 154 | |||
| 155 | |||
| 156 | /* Check whether or not FD starts with a #!, and return the executable | ||
| 157 | to load if it does. Value is NAME if no interpreter character was | ||
| 158 | found, or the interpreter otherwise. Value is NULL upon an IO | ||
| 159 | error. | ||
| 160 | |||
| 161 | If an additional command line argument is specified, place it in | ||
| 162 | *EXTRA. */ | ||
| 163 | |||
| 164 | static const char * | ||
| 165 | check_interpreter (const char *name, int fd, const char **extra) | ||
| 166 | { | ||
| 167 | static char buffer[PATH_MAX], *start; | ||
| 168 | char first[2], *end, *ws; | ||
| 169 | ssize_t rc; | ||
| 170 | |||
| 171 | /* Read the first character. */ | ||
| 172 | rc = read (fd, &first, 2); | ||
| 173 | |||
| 174 | if (rc != 2) | ||
| 175 | goto fail; | ||
| 176 | |||
| 177 | if (first[0] != '#' || first[1] != '!') | ||
| 178 | goto nomatch; | ||
| 179 | |||
| 180 | rc = read (fd, buffer, PATH_MAX); | ||
| 181 | |||
| 182 | if (rc < 0) | ||
| 183 | goto fail; | ||
| 184 | |||
| 185 | /* Strip leading whitespace. */ | ||
| 186 | start = buffer; | ||
| 187 | while (*start && ((unsigned char) *start) < 128 && isspace (*start)) | ||
| 188 | ++start; | ||
| 189 | |||
| 190 | /* Look for a newline character. */ | ||
| 191 | end = memchr (start, '\n', rc); | ||
| 192 | |||
| 193 | if (!end) | ||
| 194 | goto fail; | ||
| 195 | |||
| 196 | /* The string containing the interpreter is now in start. NULL | ||
| 197 | terminate it. */ | ||
| 198 | *end = '\0'; | ||
| 199 | |||
| 200 | /* Now look for any whitespace characters. */ | ||
| 201 | ws = strchr (start, ' '); | ||
| 202 | |||
| 203 | /* If there's no whitespace, return the entire start. */ | ||
| 204 | |||
| 205 | if (!ws) | ||
| 206 | { | ||
| 207 | if (lseek (fd, 0, SEEK_SET)) | ||
| 208 | goto fail; | ||
| 209 | |||
| 210 | return start; | ||
| 211 | } | ||
| 212 | |||
| 213 | /* Otherwise, split the string at the whitespace and return the | ||
| 214 | additional argument. */ | ||
| 215 | *ws = '\0'; | ||
| 216 | |||
| 217 | if (lseek (fd, 0, SEEK_SET)) | ||
| 218 | goto fail; | ||
| 219 | |||
| 220 | *extra = ws + 1; | ||
| 221 | return start; | ||
| 222 | |||
| 223 | nomatch: | ||
| 224 | /* There's no interpreter. */ | ||
| 225 | if (lseek (fd, 0, SEEK_SET)) | ||
| 226 | goto fail; | ||
| 227 | |||
| 228 | return name; | ||
| 229 | |||
| 230 | fail: | ||
| 231 | errno = ENOEXEC; | ||
| 232 | return NULL; | ||
| 233 | } | ||
| 234 | |||
| 235 | /* Static area used to store data placed on the loader's stack. */ | ||
| 236 | static char loader_area[65536]; | ||
| 237 | |||
| 238 | /* Number of bytes used in that area. */ | ||
| 239 | static int loader_area_used; | ||
| 240 | |||
| 241 | |||
| 242 | |||
| 243 | /* Structure definitions for commands placed in the loader area. | ||
| 244 | Arrange these so that each member is naturally aligned. */ | ||
| 245 | |||
| 246 | struct exec_open_command | ||
| 247 | { | ||
| 248 | /* Word identifying the type of this command. */ | ||
| 249 | USER_WORD command; | ||
| 250 | |||
| 251 | /* NULL-terminated file name follows, padded to the size of a user | ||
| 252 | word. */ | ||
| 253 | }; | ||
| 254 | |||
| 255 | struct exec_map_command | ||
| 256 | { | ||
| 257 | /* Word identifying the type of this command. */ | ||
| 258 | USER_WORD command; | ||
| 259 | |||
| 260 | /* Where the file will be mapped. */ | ||
| 261 | USER_WORD vm_address; | ||
| 262 | |||
| 263 | /* Offset into the file to map from. */ | ||
| 264 | USER_WORD file_offset; | ||
| 265 | |||
| 266 | /* Memory protection for mprotect. */ | ||
| 267 | USER_WORD protection; | ||
| 268 | |||
| 269 | /* Number of bytes to be mapped. */ | ||
| 270 | USER_WORD length; | ||
| 271 | |||
| 272 | /* Flags for mmap. */ | ||
| 273 | USER_WORD flags; | ||
| 274 | |||
| 275 | /* Number of bytes to clear at the end of this mapping. */ | ||
| 276 | USER_WORD clear; | ||
| 277 | }; | ||
| 278 | |||
| 279 | struct exec_jump_command | ||
| 280 | { | ||
| 281 | /* Word identifying the type of this command. */ | ||
| 282 | USER_WORD command; | ||
| 283 | |||
| 284 | /* Address to jump to. */ | ||
| 285 | USER_WORD entry; | ||
| 286 | |||
| 287 | /* The value of AT_ENTRY inside the aux vector. */ | ||
| 288 | USER_WORD at_entry; | ||
| 289 | |||
| 290 | /* The value of AT_PHENT inside the aux vector. */ | ||
| 291 | USER_WORD at_phent; | ||
| 292 | |||
| 293 | /* The value of AT_PHNUM inside the aux vector. */ | ||
| 294 | USER_WORD at_phnum; | ||
| 295 | |||
| 296 | /* The value of AT_PHDR inside the aux vector. */ | ||
| 297 | USER_WORD at_phdr; | ||
| 298 | |||
| 299 | /* The value of AT_BASE inside the aux vector. */ | ||
| 300 | USER_WORD at_base; | ||
| 301 | |||
| 302 | #if defined __mips__ && !defined MIPS_NABI | ||
| 303 | /* The FPU mode to apply. */ | ||
| 304 | USER_WORD fpu_mode; | ||
| 305 | #endif /* defined __mips__ && !defined MIPS_NABI */ | ||
| 306 | }; | ||
| 307 | |||
| 308 | |||
| 309 | |||
| 310 | /* Write a command to open the file NAME to the loader area. | ||
| 311 | If ALTERNATE is true, then use the command code 16 instead | ||
| 312 | of 0. Value is 1 upon failure, else 0. */ | ||
| 313 | |||
| 314 | static int | ||
| 315 | write_open_command (const char *name, bool alternate) | ||
| 316 | { | ||
| 317 | struct exec_open_command command; | ||
| 318 | size_t size; | ||
| 319 | |||
| 320 | /* First, write the command to open NAME. This is followed by NAME | ||
| 321 | itself, padded to sizeof (USER_WORD) bytes. */ | ||
| 322 | |||
| 323 | command.command = alternate ? 16 : 0; | ||
| 324 | if (sizeof loader_area - loader_area_used < sizeof command) | ||
| 325 | return 1; | ||
| 326 | memcpy (loader_area + loader_area_used, &command, sizeof command); | ||
| 327 | loader_area_used += sizeof command; | ||
| 328 | |||
| 329 | /* Calculate the length of NAME. */ | ||
| 330 | size = strlen (name) + 1; | ||
| 331 | |||
| 332 | /* Round it up. */ | ||
| 333 | size = ((size + (sizeof (USER_WORD) - 1)) | ||
| 334 | & ~(sizeof (USER_WORD) - 1)); | ||
| 335 | |||
| 336 | if (sizeof loader_area - loader_area_used < size) | ||
| 337 | return 1; | ||
| 338 | |||
| 339 | /* Now copy name to the loader area, filling the padding with NULL | ||
| 340 | bytes. */ | ||
| 341 | strncpy (loader_area + loader_area_used, name, size); | ||
| 342 | |||
| 343 | /* Increase loader_area_used. */ | ||
| 344 | loader_area_used += size; | ||
| 345 | return 0; | ||
| 346 | } | ||
| 347 | |||
| 348 | /* Write the commands necessary to map the executable file into memory | ||
| 349 | for the given PT_LOAD program HEADER. Value is 1 upon failure, | ||
| 350 | else 0. If USE_ALTERNATE, use the command code 17 instead of | ||
| 351 | 1. | ||
| 352 | |||
| 353 | Apply the given OFFSET to virtual addresses that will be mapped. */ | ||
| 354 | |||
| 355 | static int | ||
| 356 | write_load_command (program_header *header, bool use_alternate, | ||
| 357 | USER_WORD offset) | ||
| 358 | { | ||
| 359 | struct exec_map_command command; | ||
| 360 | struct exec_map_command command1; | ||
| 361 | USER_WORD start, end; | ||
| 362 | bool need_command1; | ||
| 363 | static long pagesize; | ||
| 364 | |||
| 365 | /* First, write the commands necessary to map the specified segment | ||
| 366 | itself. | ||
| 367 | |||
| 368 | This is the area between header->p_vaddr and header->p_filesz, | ||
| 369 | rounded up to the page size. */ | ||
| 370 | |||
| 371 | #ifndef PAGE_MASK | ||
| 372 | /* This system doesn't define a fixed page size. */ | ||
| 373 | |||
| 374 | #ifdef HAVE_GETPAGESIZE | ||
| 375 | if (!pagesize) | ||
| 376 | pagesize = getpagesize (); | ||
| 377 | #else /* HAVE_GETPAGESIZE */ | ||
| 378 | if (!pagesize) | ||
| 379 | pagesize = sysconf (_SC_PAGESIZE); | ||
| 380 | |||
| 381 | #define PAGE_MASK (~(pagesize - 1)) | ||
| 382 | #define PAGE_SIZE (pagesize) | ||
| 383 | #endif /* HAVE_GETPAGESIZE */ | ||
| 384 | #endif /* PAGE_MASK */ | ||
| 385 | |||
| 386 | start = header->p_vaddr & PAGE_MASK; | ||
| 387 | end = ((header->p_vaddr + header->p_filesz | ||
| 388 | + PAGE_SIZE) | ||
| 389 | & PAGE_MASK); | ||
| 390 | |||
| 391 | command.command = use_alternate ? 17 : 1; | ||
| 392 | command.vm_address = start; | ||
| 393 | command.file_offset = header->p_offset & PAGE_MASK; | ||
| 394 | command.protection = 0; | ||
| 395 | command.length = end - start; | ||
| 396 | command.clear = 0; | ||
| 397 | command.flags = MAP_PRIVATE | MAP_FIXED; | ||
| 398 | |||
| 399 | /* Apply the memory protection specified in the header. */ | ||
| 400 | |||
| 401 | if (header->p_flags & 4) /* PF_R */ | ||
| 402 | command.protection |= PROT_READ; | ||
| 403 | |||
| 404 | if (header->p_flags & 2) /* PF_W */ | ||
| 405 | command.protection |= PROT_WRITE; | ||
| 406 | |||
| 407 | if (header->p_flags & 1) /* PF_X */ | ||
| 408 | command.protection |= PROT_EXEC; | ||
| 409 | |||
| 410 | /* Next, write any command necessary to map pages in the area | ||
| 411 | between p_filesz and p_memsz. */ | ||
| 412 | need_command1 = false; | ||
| 413 | |||
| 414 | if (header->p_memsz > header->p_filesz) | ||
| 415 | { | ||
| 416 | /* If there are bytes after end which need to be initialized, do | ||
| 417 | that now. */ | ||
| 418 | command.clear = end - header->p_vaddr - header->p_filesz; | ||
| 419 | start = end; | ||
| 420 | end = header->p_vaddr + header->p_memsz + PAGE_SIZE; | ||
| 421 | end &= PAGE_MASK; | ||
| 422 | |||
| 423 | if (end > start) | ||
| 424 | { | ||
| 425 | command1.command = 4; | ||
| 426 | command1.vm_address = start; | ||
| 427 | command1.file_offset = 0; | ||
| 428 | command1.length = end - start; | ||
| 429 | command1.clear = 0; | ||
| 430 | command1.protection = command.protection; | ||
| 431 | command1.flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED; | ||
| 432 | need_command1 = true; | ||
| 433 | } | ||
| 434 | } | ||
| 435 | |||
| 436 | /* Apply the offset to both commands if necessary. */ | ||
| 437 | |||
| 438 | if (offset) | ||
| 439 | { | ||
| 440 | if (need_command1) | ||
| 441 | command1.vm_address += offset; | ||
| 442 | |||
| 443 | command.vm_address += offset; | ||
| 444 | } | ||
| 445 | |||
| 446 | /* Write both commands. */ | ||
| 447 | |||
| 448 | if (sizeof loader_area - loader_area_used < sizeof command) | ||
| 449 | return 1; | ||
| 450 | |||
| 451 | memcpy (loader_area + loader_area_used, &command, | ||
| 452 | sizeof command); | ||
| 453 | loader_area_used += sizeof command; | ||
| 454 | |||
| 455 | if (!need_command1) | ||
| 456 | return 0; | ||
| 457 | |||
| 458 | if (sizeof loader_area - loader_area_used < sizeof command1) | ||
| 459 | return 1; | ||
| 460 | |||
| 461 | memcpy (loader_area + loader_area_used, &command1, | ||
| 462 | sizeof command1); | ||
| 463 | loader_area_used += sizeof command1; | ||
| 464 | |||
| 465 | return 0; | ||
| 466 | } | ||
| 467 | |||
| 468 | #if defined __mips__ && !defined MIPS_NABI | ||
| 469 | |||
| 470 | /* Static storage used for MIPS ABI flags. */ | ||
| 471 | static struct mips_elf_abi_flags exec_abi, interpreter_abi; | ||
| 472 | |||
| 473 | /* Static storage for interpreter headers. */ | ||
| 474 | static elf_header exec_interpreter_header; | ||
| 475 | |||
| 476 | /* Pointer to the ELF header of this executable's interpreter. */ | ||
| 477 | static elf_header *interpreter_header; | ||
| 478 | |||
| 479 | /* Pointer to any PT_MIPS_ABIFLAGS program header found in the | ||
| 480 | executable itself. */ | ||
| 481 | static struct mips_elf_abi_flags *exec_abiflags; | ||
| 482 | |||
| 483 | /* Pointer to any PT_MIPS_ABIFLAGS program header found in the | ||
| 484 | executable's ELF interpreter. */ | ||
| 485 | static struct mips_elf_abi_flags *interpreter_abiflags; | ||
| 486 | |||
| 487 | #endif /* defined __mips__ && !defined MIPS_NABI */ | ||
| 488 | |||
| 489 | /* Process the specified program HEADER; HEADER is from the ELF | ||
| 490 | interpreter of another executable. FD is the executable file from | ||
| 491 | which it is being read, NAME is its file name, and ELF_HEADER is | ||
| 492 | its header. | ||
| 493 | |||
| 494 | If ELF_HEADER->e_type is ET_DYN, add the base address for position | ||
| 495 | independent interpreter code to virtual addresses. | ||
| 496 | |||
| 497 | Value is 1 upon failure, else 0. */ | ||
| 498 | |||
| 499 | static int | ||
| 500 | process_interpreter_1 (const char *name, int fd, | ||
| 501 | program_header *header, | ||
| 502 | elf_header *elf_header) | ||
| 503 | { | ||
| 504 | int rc; | ||
| 505 | #if defined __mips__ && !defined MIPS_NABI | ||
| 506 | ssize_t rc1; | ||
| 507 | #endif /* defined __mips__ && !defined MIPS_NABI */ | ||
| 508 | |||
| 509 | switch (header->p_type) | ||
| 510 | { | ||
| 511 | default: /* PT_NULL, PT_NOTE, PT_DYNAMIC, PT_INTERP, et cetera */ | ||
| 512 | rc = 0; | ||
| 513 | break; | ||
| 514 | |||
| 515 | case 1: /* PT_LOAD */ | ||
| 516 | /* This describes a segment in the file that must be loaded. | ||
| 517 | Write the appropriate load command. */ | ||
| 518 | |||
| 519 | if (elf_header->e_type == 3) /* ET_DYN */ | ||
| 520 | rc = write_load_command (header, true, | ||
| 521 | INTERPRETER_BASE); | ||
| 522 | else | ||
| 523 | rc = write_load_command (header, true, 0); | ||
| 524 | |||
| 525 | break; | ||
| 526 | |||
| 527 | #if defined __mips__ && !defined MIPS_NABI | ||
| 528 | case 0x70000003: /* PT_MIPS_ABIFLAGS */ | ||
| 529 | /* Record this header for later use. */ | ||
| 530 | rc1 = pread (fd, &interpreter_abi, sizeof interpreter_abi, | ||
| 531 | header->p_offset); | ||
| 532 | |||
| 533 | if (rc1 != sizeof interpreter_abi) | ||
| 534 | return 1; | ||
| 535 | |||
| 536 | interpreter_abiflags = &interpreter_abi; | ||
| 537 | rc = 0; | ||
| 538 | #endif /* defined __mips__ && !defined MIPS_NABI */ | ||
| 539 | } | ||
| 540 | |||
| 541 | return rc; | ||
| 542 | } | ||
| 543 | |||
| 544 | /* Read the ELF interpreter specified in the given program header from | ||
| 545 | FD, and append the commands necessary to load it to the load area. | ||
| 546 | Then, return the interpreter entry point in *ENTRY. | ||
| 547 | |||
| 548 | Value is 1 upon failure, else 0. */ | ||
| 549 | |||
| 550 | static int | ||
| 551 | process_interpreter (int fd, program_header *prog_header, | ||
| 552 | USER_WORD *entry) | ||
| 553 | { | ||
| 554 | char buffer[PATH_MAX + 1]; | ||
| 555 | int rc, size, i; | ||
| 556 | elf_header header; | ||
| 557 | program_header program; | ||
| 558 | |||
| 559 | /* Read the interpreter name. */ | ||
| 560 | size = MIN (prog_header->p_filesz, PATH_MAX); | ||
| 561 | rc = pread (fd, buffer, size, prog_header->p_offset); | ||
| 562 | if (rc < size) | ||
| 563 | return 1; | ||
| 564 | |||
| 565 | /* Make sure the name is NULL terminated. */ | ||
| 566 | buffer[size] = '\0'; | ||
| 567 | |||
| 568 | /* Check if the file is executable. This is unfortunately not | ||
| 569 | atomic. */ | ||
| 570 | |||
| 571 | if (access (buffer, X_OK)) | ||
| 572 | return 1; | ||
| 573 | |||
| 574 | /* Read the interpreter's header much like exec_0. | ||
| 575 | |||
| 576 | However, use special command codes in `process_program_header' if | ||
| 577 | it is position independent. That way, the loader knows it should | ||
| 578 | use the open interpreter instead. */ | ||
| 579 | |||
| 580 | fd = open (buffer, O_RDONLY); | ||
| 581 | |||
| 582 | if (fd < 0) | ||
| 583 | return 1; | ||
| 584 | |||
| 585 | rc = read (fd, &header, sizeof header); | ||
| 586 | |||
| 587 | if (rc < sizeof header) | ||
| 588 | goto fail; | ||
| 589 | |||
| 590 | #if defined __mips__ && !defined MIPS_NABI | ||
| 591 | /* Record this interpreter's header for later use determining the | ||
| 592 | floating point ABI. */ | ||
| 593 | exec_interpreter_header = header; | ||
| 594 | interpreter_header = &exec_interpreter_header; | ||
| 595 | #endif /* defined __mips__ && !defined MIPS_NABI */ | ||
| 596 | |||
| 597 | /* Verify that this is indeed an ELF file. */ | ||
| 598 | |||
| 599 | if (header.e_ident[0] != 0x7f | ||
| 600 | || header.e_ident[1] != 'E' | ||
| 601 | || header.e_ident[2] != 'L' | ||
| 602 | || header.e_ident[3] != 'F') | ||
| 603 | goto fail; | ||
| 604 | |||
| 605 | /* Now check that the class is correct. */ | ||
| 606 | #ifdef EXEC_64 | ||
| 607 | if (header.e_ident[4] != 2) | ||
| 608 | goto fail; | ||
| 609 | #else /* !EXEC_64 */ | ||
| 610 | if (header.e_ident[4] != 1) | ||
| 611 | goto fail; | ||
| 612 | #endif /* EXEC_64 */ | ||
| 613 | |||
| 614 | /* And the endianness. */ | ||
| 615 | #ifndef WORDS_BIGENDIAN | ||
| 616 | if (header.e_ident[5] != 1) | ||
| 617 | goto fail; | ||
| 618 | #else /* WORDS_BIGENDIAN */ | ||
| 619 | if (header.e_ident[5] != 2) | ||
| 620 | goto fail; | ||
| 621 | #endif /* EXEC_64 */ | ||
| 622 | |||
| 623 | /* Check that this is an executable. */ | ||
| 624 | if (header.e_type != 2 && header.e_type != 3) | ||
| 625 | goto fail; | ||
| 626 | |||
| 627 | /* Now check that the ELF program header makes sense. */ | ||
| 628 | if (header.e_phnum > 0xffff | ||
| 629 | || (header.e_phentsize | ||
| 630 | != sizeof (program_header))) | ||
| 631 | goto fail; | ||
| 632 | |||
| 633 | if (write_open_command (buffer, true)) | ||
| 634 | goto fail; | ||
| 635 | |||
| 636 | for (i = 0; i < header.e_phnum; ++i) | ||
| 637 | { | ||
| 638 | rc = read (fd, &program, sizeof program); | ||
| 639 | if (rc < sizeof program) | ||
| 640 | goto fail; | ||
| 641 | |||
| 642 | if (process_interpreter_1 (buffer, fd, &program, | ||
| 643 | &header)) | ||
| 644 | goto fail; | ||
| 645 | } | ||
| 646 | |||
| 647 | if (header.e_type == 3) /* ET_DYN */ | ||
| 648 | *entry = header.e_entry + INTERPRETER_BASE; | ||
| 649 | else | ||
| 650 | *entry = header.e_entry; | ||
| 651 | |||
| 652 | close (fd); | ||
| 653 | return 0; | ||
| 654 | |||
| 655 | fail: | ||
| 656 | close (fd); | ||
| 657 | return 1; | ||
| 658 | } | ||
| 659 | |||
| 660 | /* Process the specified program HEADER. FD is the executable file | ||
| 661 | from which it is being read, NAME is its file name, and ELF_HEADER | ||
| 662 | is its header. | ||
| 663 | |||
| 664 | If ELF_HEADER->e_type is ET_DYN, add the base address for position | ||
| 665 | independent code to virtual addresses. | ||
| 666 | |||
| 667 | If OFFSET is non-NULL, and *OFFSET is -1, write the virtual address | ||
| 668 | of HEADER if it describes a PT_LOAD segment. | ||
| 669 | |||
| 670 | If an interpreter is found, set *ENTRY to its entry point. | ||
| 671 | |||
| 672 | Value is 1 upon failure, else 0. */ | ||
| 673 | |||
| 674 | static int | ||
| 675 | process_program_header (const char *name, int fd, | ||
| 676 | program_header *header, | ||
| 677 | elf_header *elf_header, | ||
| 678 | USER_WORD *entry, | ||
| 679 | USER_WORD *offset) | ||
| 680 | { | ||
| 681 | int rc; | ||
| 682 | #if defined __mips__ && !defined MIPS_NABI | ||
| 683 | ssize_t rc1; | ||
| 684 | #endif /* defined __mips__ && !defined MIPS_NABI */ | ||
| 685 | |||
| 686 | switch (header->p_type) | ||
| 687 | { | ||
| 688 | default: /* PT_NULL, PT_NOTE, PT_DYNAMIC, et cetera */ | ||
| 689 | rc = 0; | ||
| 690 | break; | ||
| 691 | |||
| 692 | case 1: /* PT_LOAD */ | ||
| 693 | /* This describes a segment in the file that must be loaded. | ||
| 694 | Write the appropriate load command. */ | ||
| 695 | |||
| 696 | if (elf_header->e_type == 3) /* ET_DYN */ | ||
| 697 | { | ||
| 698 | rc = write_load_command (header, false, | ||
| 699 | EXECUTABLE_BASE); | ||
| 700 | |||
| 701 | if (!rc && offset && *offset == (USER_WORD) -1) | ||
| 702 | *offset = EXECUTABLE_BASE + header->p_vaddr; | ||
| 703 | } | ||
| 704 | else | ||
| 705 | { | ||
| 706 | rc = write_load_command (header, false, 0); | ||
| 707 | |||
| 708 | if (!rc && offset && *offset == (USER_WORD) -1) | ||
| 709 | *offset = header->p_vaddr; | ||
| 710 | } | ||
| 711 | |||
| 712 | break; | ||
| 713 | |||
| 714 | case 3: /* PT_INTERP */ | ||
| 715 | /* This describes another executable that must be loaded. Open | ||
| 716 | the interpreter and process each of its headers as well. */ | ||
| 717 | rc = process_interpreter (fd, header, entry); | ||
| 718 | break; | ||
| 719 | |||
| 720 | case 1685382481: /* PT_GNU_STACK */ | ||
| 721 | /* TODO */ | ||
| 722 | rc = 0; | ||
| 723 | break; | ||
| 724 | |||
| 725 | #if defined __mips__ && !defined MIPS_NABI | ||
| 726 | case 0x70000003: /* PT_MIPS_ABIFLAGS */ | ||
| 727 | /* Record this header for later use. */ | ||
| 728 | rc1 = pread (fd, &exec_abi, sizeof exec_abi, | ||
| 729 | header->p_offset); | ||
| 730 | |||
| 731 | if (rc1 != sizeof exec_abi) | ||
| 732 | return 1; | ||
| 733 | |||
| 734 | exec_abiflags = &exec_abi; | ||
| 735 | rc = 0; | ||
| 736 | #endif /* defined __mips__ && !defined MIPS_NABI */ | ||
| 737 | } | ||
| 738 | |||
| 739 | return rc; | ||
| 740 | } | ||
| 741 | |||
| 742 | /* Prepend one or two extra arguments ARG1 and ARG2 to a pending | ||
| 743 | execve system call. Replace the argument immediately after | ||
| 744 | with ARG3. | ||
| 745 | |||
| 746 | TRACEE is the tracee performing the system call, and REGS are its | ||
| 747 | current user registers. Value is 1 upon failure, else 0. */ | ||
| 748 | |||
| 749 | static int | ||
| 750 | insert_args (struct exec_tracee *tracee, USER_REGS_STRUCT *regs, | ||
| 751 | const char *arg1, const char *arg2, const char *arg3) | ||
| 752 | { | ||
| 753 | USER_WORD argv, argc, word, new; | ||
| 754 | USER_WORD new1, new2, new3, i; | ||
| 755 | size_t text_size, effective_size; | ||
| 756 | USER_REGS_STRUCT original; | ||
| 757 | |||
| 758 | /* First, get a pointer to the current argument vector. */ | ||
| 759 | argv = regs->SYSCALL_ARG1_REG; | ||
| 760 | |||
| 761 | /* Now figure out how many arguments there are. */ | ||
| 762 | argc = 0; | ||
| 763 | while (true) | ||
| 764 | { | ||
| 765 | /* Clear errno. PTRACE_PEEKDATA returns the word read the same | ||
| 766 | way failure indications are returned, so the only way to | ||
| 767 | catch IO errors is by clearing errno before the call to | ||
| 768 | ptrace and checking it afterwards. */ | ||
| 769 | |||
| 770 | errno = 0; | ||
| 771 | word = ptrace (PTRACE_PEEKDATA, tracee->pid, | ||
| 772 | (void *) argv, NULL); | ||
| 773 | argv += sizeof (USER_WORD); | ||
| 774 | |||
| 775 | if (errno) | ||
| 776 | return 1; | ||
| 777 | |||
| 778 | if (!word) | ||
| 779 | break; | ||
| 780 | |||
| 781 | ++argc; | ||
| 782 | }; | ||
| 783 | |||
| 784 | /* Allocate enough to hold that many arguments, alongside the argc | ||
| 785 | text. */ | ||
| 786 | |||
| 787 | text_size = (strlen (arg1) + 1 | ||
| 788 | + (arg2 ? strlen (arg2) + 1 : 0) | ||
| 789 | + strlen (arg3) + 1); | ||
| 790 | |||
| 791 | /* Round it up to the user word size. */ | ||
| 792 | text_size += sizeof (USER_WORD) - 1; | ||
| 793 | text_size &= ~(sizeof (USER_WORD) - 1); | ||
| 794 | |||
| 795 | /* Now allocate the new argv. Make sure argc is at least 1; it | ||
| 796 | needs to hold ARG3. */ | ||
| 797 | |||
| 798 | effective_size = sizeof word * (MAX (1, argc) + 2) + text_size; | ||
| 799 | |||
| 800 | if (arg2) | ||
| 801 | effective_size += sizeof word; | ||
| 802 | |||
| 803 | /* Copy regs to original so that user_alloca knows it should append | ||
| 804 | the ABI red zone. */ | ||
| 805 | |||
| 806 | memcpy (&original, regs, sizeof *regs); | ||
| 807 | new = user_alloca (tracee, &original, regs, | ||
| 808 | effective_size); | ||
| 809 | |||
| 810 | if (!new) | ||
| 811 | goto fail; | ||
| 812 | |||
| 813 | /* Figure out where argv starts. */ | ||
| 814 | |||
| 815 | new3 = new + text_size; | ||
| 816 | |||
| 817 | /* Now write the first two strings. */ | ||
| 818 | |||
| 819 | new1 = new + strlen (arg1) + 1; | ||
| 820 | new2 = new1 + (arg2 ? strlen (arg2) + 1 : 0); | ||
| 821 | |||
| 822 | if (user_copy (tracee, (const unsigned char *) arg1, | ||
| 823 | new, new1 - new)) | ||
| 824 | goto fail; | ||
| 825 | |||
| 826 | if (arg2 && user_copy (tracee, (const unsigned char *) arg2, | ||
| 827 | new1, new2 - new1)) | ||
| 828 | goto fail; | ||
| 829 | |||
| 830 | /* Write the replacement arg3, the file name of the executable. */ | ||
| 831 | |||
| 832 | if (user_copy (tracee, (const unsigned char *) arg3, | ||
| 833 | new2, new3 - new2)) | ||
| 834 | goto fail; | ||
| 835 | |||
| 836 | /* Start copying argv back to new2. First, write the one or two new | ||
| 837 | arguments. */ | ||
| 838 | |||
| 839 | if (ptrace (PTRACE_POKETEXT, tracee->pid, | ||
| 840 | (void *) new3, (void *) new)) | ||
| 841 | goto fail; | ||
| 842 | |||
| 843 | new3 += sizeof new3; | ||
| 844 | |||
| 845 | if (arg2 && ptrace (PTRACE_POKETEXT, tracee->pid, | ||
| 846 | (void *) new3, (void *) new1)) | ||
| 847 | goto fail; | ||
| 848 | else if (arg2) | ||
| 849 | new3 += sizeof new3; | ||
| 850 | |||
| 851 | /* Next, write the third argument. */ | ||
| 852 | |||
| 853 | if (ptrace (PTRACE_POKETEXT, tracee->pid, (void *) new3, | ||
| 854 | (void *) new2)) | ||
| 855 | goto fail; | ||
| 856 | |||
| 857 | new3 += sizeof new3; | ||
| 858 | |||
| 859 | /* Copy the remaining arguments back. */ | ||
| 860 | |||
| 861 | argv = regs->SYSCALL_ARG1_REG; | ||
| 862 | |||
| 863 | if (argc) | ||
| 864 | { | ||
| 865 | /* Make sure the trailing NULL is included. */ | ||
| 866 | argc += 1; | ||
| 867 | |||
| 868 | /* Now copy each argument in argv, starting from argv[1]. */ | ||
| 869 | |||
| 870 | for (i = 1; i < argc; ++i) | ||
| 871 | { | ||
| 872 | /* Read one argument. */ | ||
| 873 | word = ptrace (PTRACE_PEEKDATA, tracee->pid, | ||
| 874 | (void *) (argv + i * sizeof argv), NULL); | ||
| 875 | |||
| 876 | /* Write one argument, then increment new3. */ | ||
| 877 | |||
| 878 | if (ptrace (PTRACE_POKETEXT, tracee->pid, | ||
| 879 | (void *) new3, (void *) word)) | ||
| 880 | goto fail; | ||
| 881 | |||
| 882 | new3 += sizeof new3; | ||
| 883 | } | ||
| 884 | } | ||
| 885 | else | ||
| 886 | { | ||
| 887 | /* Just write the trailing NULL. */ | ||
| 888 | |||
| 889 | if (ptrace (PTRACE_POKETEXT, tracee->pid, | ||
| 890 | (void *) new3, (void *) 0)) | ||
| 891 | goto fail; | ||
| 892 | |||
| 893 | new3 += sizeof new3; | ||
| 894 | } | ||
| 895 | |||
| 896 | /* Assert that new3 is not out of bounds. */ | ||
| 897 | assert (new3 == new + effective_size); | ||
| 898 | |||
| 899 | /* And that it is properly aligned. */ | ||
| 900 | assert (!(new3 & (sizeof new3 - 2))); | ||
| 901 | |||
| 902 | /* Now modify the system call argument to point to new + | ||
| 903 | text_size. */ | ||
| 904 | |||
| 905 | regs->SYSCALL_ARG1_REG = new + text_size; | ||
| 906 | |||
| 907 | #ifdef __aarch64__ | ||
| 908 | if (aarch64_set_regs (tracee->pid, regs, false)) | ||
| 909 | goto fail; | ||
| 910 | #else /* !__aarch64__ */ | ||
| 911 | if (ptrace (PTRACE_SETREGS, tracee->pid, NULL, regs)) | ||
| 912 | goto fail; | ||
| 913 | #endif /* __aarch64__ */ | ||
| 914 | |||
| 915 | /* Success. */ | ||
| 916 | |||
| 917 | return 0; | ||
| 918 | |||
| 919 | fail: | ||
| 920 | /* Restore the original stack pointer. */ | ||
| 921 | #ifdef __aarch64__ | ||
| 922 | aarch64_set_regs (tracee->pid, &original, false); | ||
| 923 | #else /* !__aarch64__ */ | ||
| 924 | ptrace (PTRACE_SETREGS, tracee->pid, NULL, &original); | ||
| 925 | #endif /* __aarch64__ */ | ||
| 926 | errno = ENOMEM; | ||
| 927 | return 1; | ||
| 928 | } | ||
| 929 | |||
| 930 | |||
| 931 | |||
| 932 | /* Format PID, an unsigned process identifier, in base 10. Place the | ||
| 933 | result in *IN, and return a pointer to the byte after the | ||
| 934 | result. REM should be NULL. */ | ||
| 935 | |||
| 936 | static char * | ||
| 937 | format_pid (char *in, unsigned int pid) | ||
| 938 | { | ||
| 939 | unsigned int digits[32], *fill; | ||
| 940 | |||
| 941 | fill = digits; | ||
| 942 | |||
| 943 | for (; pid != 0; pid = pid / 10) | ||
| 944 | *fill++ = pid % 10; | ||
| 945 | |||
| 946 | /* Insert 0 if the number would otherwise be empty. */ | ||
| 947 | |||
| 948 | if (fill == digits) | ||
| 949 | *fill++ = 0; | ||
| 950 | |||
| 951 | while (fill != digits) | ||
| 952 | { | ||
| 953 | --fill; | ||
| 954 | *in++ = '0' + *fill; | ||
| 955 | } | ||
| 956 | |||
| 957 | *in = '\0'; | ||
| 958 | return in; | ||
| 959 | } | ||
| 960 | |||
| 961 | /* Return a sequence of actions required to load the executable under | ||
| 962 | the file NAME for the given TRACEE. First, see if the file starts | ||
| 963 | with #!; in that case, find the program to open and use that | ||
| 964 | instead. | ||
| 965 | |||
| 966 | If REENTRANT is not defined, NAME is actually a buffer of size | ||
| 967 | PATH_MAX + 80. In that case, copy over the file name actually | ||
| 968 | opened. | ||
| 969 | |||
| 970 | Next, read the executable header, and add the necessary memory | ||
| 971 | mappings for each file. Finally, return the action data and its | ||
| 972 | size in *SIZE. | ||
| 973 | |||
| 974 | Finally, use REGS to add the required interpreter arguments to the | ||
| 975 | caller's argv. | ||
| 976 | |||
| 977 | Value is NULL upon failure, with errno set accordingly. */ | ||
| 978 | |||
| 979 | char * | ||
| 980 | exec_0 (char *name, struct exec_tracee *tracee, | ||
| 981 | size_t *size, USER_REGS_STRUCT *regs) | ||
| 982 | { | ||
| 983 | int fd, rc, i; | ||
| 984 | elf_header header; | ||
| 985 | const char *interpreter_name, *extra; | ||
| 986 | program_header program; | ||
| 987 | USER_WORD entry, program_entry, offset; | ||
| 988 | USER_WORD header_offset; | ||
| 989 | struct exec_jump_command jump; | ||
| 990 | #if defined __mips__ && !defined MIPS_NABI | ||
| 991 | int fpu_mode; | ||
| 992 | #endif /* defined __mips__ && !defined MIPS_NABI */ | ||
| 993 | char buffer[80], buffer1[PATH_MAX + 80], *rewrite; | ||
| 994 | ssize_t link_size; | ||
| 995 | size_t remaining; | ||
| 996 | |||
| 997 | /* If the process is trying to run /proc/self/exe, make it run | ||
| 998 | itself instead. */ | ||
| 999 | |||
| 1000 | if (!strcmp (name, "/proc/self/exe") && tracee->exec_file) | ||
| 1001 | { | ||
| 1002 | strncpy (name, tracee->exec_file, PATH_MAX - 1); | ||
| 1003 | name[PATH_MAX] = '\0'; | ||
| 1004 | } | ||
| 1005 | else | ||
| 1006 | { | ||
| 1007 | /* If name is not absolute, then make it relative to TRACEE's | ||
| 1008 | cwd. Use stpcpy, as sprintf is not reentrant. */ | ||
| 1009 | |||
| 1010 | if (name[0] && name[0] != '/') | ||
| 1011 | { | ||
| 1012 | /* Clear `buffer'. */ | ||
| 1013 | memset (buffer, 0, sizeof buffer); | ||
| 1014 | memset (buffer1, 0, sizeof buffer); | ||
| 1015 | |||
| 1016 | /* Copy over /proc, the PID, and /cwd/. */ | ||
| 1017 | rewrite = stpcpy (buffer, "/proc/"); | ||
| 1018 | rewrite = format_pid (rewrite, tracee->pid); | ||
| 1019 | strcpy (rewrite, "/cwd"); | ||
| 1020 | |||
| 1021 | /* Resolve this symbolic link. */ | ||
| 1022 | |||
| 1023 | link_size = readlink (buffer, buffer1, | ||
| 1024 | PATH_MAX + 1); | ||
| 1025 | |||
| 1026 | if (link_size < 0) | ||
| 1027 | return NULL; | ||
| 1028 | |||
| 1029 | /* Check that the name is a reasonable size. */ | ||
| 1030 | |||
| 1031 | if (link_size > PATH_MAX) | ||
| 1032 | { | ||
| 1033 | /* The name is too long. */ | ||
| 1034 | errno = ENAMETOOLONG; | ||
| 1035 | return NULL; | ||
| 1036 | } | ||
| 1037 | |||
| 1038 | /* Add a directory separator if necessary. */ | ||
| 1039 | |||
| 1040 | if (!link_size || buffer1[link_size - 1] != '/') | ||
| 1041 | buffer1[link_size] = '/', link_size++; | ||
| 1042 | |||
| 1043 | rewrite = buffer1 + link_size; | ||
| 1044 | remaining = buffer1 + sizeof buffer1 - rewrite - 1; | ||
| 1045 | rewrite = stpncpy (rewrite, name, remaining); | ||
| 1046 | |||
| 1047 | /* Replace name with buffer1. */ | ||
| 1048 | #ifndef REENTRANT | ||
| 1049 | strcpy (name, buffer1); | ||
| 1050 | #endif /* REENTRANT */ | ||
| 1051 | } | ||
| 1052 | } | ||
| 1053 | |||
| 1054 | /* Check that the file is accessible and executable. */ | ||
| 1055 | |||
| 1056 | if (access (name, X_OK)) | ||
| 1057 | return NULL; | ||
| 1058 | |||
| 1059 | fd = open (name, O_RDONLY); | ||
| 1060 | if (fd < 0) | ||
| 1061 | return NULL; | ||
| 1062 | |||
| 1063 | /* Now read the header. */ | ||
| 1064 | |||
| 1065 | extra = NULL; | ||
| 1066 | interpreter_name = check_interpreter (name, fd, &extra); | ||
| 1067 | if (!interpreter_name) | ||
| 1068 | goto fail; | ||
| 1069 | |||
| 1070 | /* Open the interpreter instead, if necessary. */ | ||
| 1071 | if (interpreter_name != name) | ||
| 1072 | { | ||
| 1073 | close (fd); | ||
| 1074 | fd = open (interpreter_name, O_RDONLY); | ||
| 1075 | if (fd < 0) | ||
| 1076 | return NULL; | ||
| 1077 | |||
| 1078 | /* Now, rewrite the argument list to include `interpreter_name' | ||
| 1079 | and perhaps `extra'. */ | ||
| 1080 | |||
| 1081 | if (insert_args (tracee, regs, interpreter_name, | ||
| 1082 | extra, name)) | ||
| 1083 | goto fail1; | ||
| 1084 | } | ||
| 1085 | |||
| 1086 | rc = read (fd, &header, sizeof header); | ||
| 1087 | |||
| 1088 | if (rc < sizeof header) | ||
| 1089 | goto fail1; | ||
| 1090 | |||
| 1091 | /* Verify that this is indeed an ELF file. */ | ||
| 1092 | |||
| 1093 | if (header.e_ident[0] != 0x7f | ||
| 1094 | || header.e_ident[1] != 'E' | ||
| 1095 | || header.e_ident[2] != 'L' | ||
| 1096 | || header.e_ident[3] != 'F') | ||
| 1097 | goto fail1; | ||
| 1098 | |||
| 1099 | /* Now check that the class is correct. */ | ||
| 1100 | #ifdef EXEC_64 | ||
| 1101 | if (header.e_ident[4] != 2) | ||
| 1102 | goto fail1; | ||
| 1103 | #else /* !EXEC_64 */ | ||
| 1104 | if (header.e_ident[4] != 1) | ||
| 1105 | goto fail1; | ||
| 1106 | #endif /* EXEC_64 */ | ||
| 1107 | |||
| 1108 | /* And the endianness. */ | ||
| 1109 | #ifndef WORDS_BIGENDIAN | ||
| 1110 | if (header.e_ident[5] != 1) | ||
| 1111 | goto fail1; | ||
| 1112 | #else /* WORDS_BIGENDIAN */ | ||
| 1113 | if (header.e_ident[5] != 2) | ||
| 1114 | goto fail1; | ||
| 1115 | #endif /* EXEC_64 */ | ||
| 1116 | |||
| 1117 | /* Check that this is an executable. */ | ||
| 1118 | if (header.e_type != 2 && header.e_type != 3) | ||
| 1119 | goto fail1; | ||
| 1120 | |||
| 1121 | /* Now check that the ELF program header makes sense. */ | ||
| 1122 | if (header.e_phnum > 0xffff | ||
| 1123 | || (header.e_phentsize | ||
| 1124 | != sizeof (program_header))) | ||
| 1125 | goto fail1; | ||
| 1126 | |||
| 1127 | /* Seek to the first program header and read each one. */ | ||
| 1128 | rc = lseek (fd, header.e_phoff, SEEK_SET); | ||
| 1129 | if (rc < 0) | ||
| 1130 | goto fail1; | ||
| 1131 | loader_area_used = 0; | ||
| 1132 | |||
| 1133 | /* Write the command used to open the executable. */ | ||
| 1134 | if (write_open_command (interpreter_name, false)) | ||
| 1135 | goto fail1; | ||
| 1136 | |||
| 1137 | /* Apply base addresses for PIC code. */ | ||
| 1138 | |||
| 1139 | if (header.e_type == 3) /* ET_DYN */ | ||
| 1140 | offset = EXECUTABLE_BASE; | ||
| 1141 | else | ||
| 1142 | offset = 0; | ||
| 1143 | |||
| 1144 | /* entry and program_entry are initially the same, but entry may be | ||
| 1145 | set to that of the interpreter if one is present. */ | ||
| 1146 | |||
| 1147 | entry = header.e_entry + offset; | ||
| 1148 | program_entry = header.e_entry; | ||
| 1149 | |||
| 1150 | #if defined __mips__ && !defined MIPS_NABI | ||
| 1151 | /* Clear MIPS ABI flags. */ | ||
| 1152 | exec_abiflags = NULL; | ||
| 1153 | interpreter_abiflags = NULL; | ||
| 1154 | interpreter_header = NULL; | ||
| 1155 | #endif /* defined __mips__ && !defined MIPS_NABI */ | ||
| 1156 | |||
| 1157 | /* Set header_offset to -1; `process_program_header' then updates it | ||
| 1158 | to that of the first mapping. */ | ||
| 1159 | header_offset = -1; | ||
| 1160 | |||
| 1161 | for (i = 0; i < header.e_phnum; ++i) | ||
| 1162 | { | ||
| 1163 | rc = read (fd, &program, sizeof program); | ||
| 1164 | if (rc < sizeof program) | ||
| 1165 | goto fail1; | ||
| 1166 | |||
| 1167 | if (process_program_header (interpreter_name, fd, | ||
| 1168 | &program, &header, | ||
| 1169 | &entry, &header_offset)) | ||
| 1170 | goto fail1; | ||
| 1171 | } | ||
| 1172 | |||
| 1173 | /* Write the entry point and program entry. */ | ||
| 1174 | |||
| 1175 | jump.command = 3; | ||
| 1176 | jump.entry = entry; | ||
| 1177 | |||
| 1178 | /* Now calculate values for the aux vector. */ | ||
| 1179 | |||
| 1180 | jump.at_entry = program_entry + offset; | ||
| 1181 | jump.at_phent = header.e_phentsize; | ||
| 1182 | jump.at_phnum = header.e_phnum; | ||
| 1183 | jump.at_base = (entry == header.e_entry + offset | ||
| 1184 | ? EXECUTABLE_BASE | ||
| 1185 | : INTERPRETER_BASE); | ||
| 1186 | |||
| 1187 | #if defined __mips__ && !defined MIPS_NABI | ||
| 1188 | /* Finally, calculate the FPU mode wanted by the executable. */ | ||
| 1189 | |||
| 1190 | if (determine_fpu_mode (&header, interpreter_header, | ||
| 1191 | &fpu_mode, exec_abiflags, | ||
| 1192 | interpreter_abiflags)) | ||
| 1193 | /* N.B. that `determine_fpu_mode' sets errno. */ | ||
| 1194 | goto fail; | ||
| 1195 | |||
| 1196 | /* If the processor is too new to support FR0 operation, place the | ||
| 1197 | executable in floating point emulation mode. */ | ||
| 1198 | |||
| 1199 | if (fpu_mode == FP_FR0 && !cpu_supports_fr0_p ()) | ||
| 1200 | fpu_mode = FP_FRE; | ||
| 1201 | |||
| 1202 | jump.fpu_mode = fpu_mode; | ||
| 1203 | #endif /* defined __mips__ && !defined MIPS_NABI */ | ||
| 1204 | |||
| 1205 | /* The offset used for at_phdr should be that of the first | ||
| 1206 | mapping. */ | ||
| 1207 | |||
| 1208 | if (header_offset == (USER_WORD) -1) | ||
| 1209 | header_offset = 0; | ||
| 1210 | |||
| 1211 | jump.at_phdr = header.e_phoff + header_offset; | ||
| 1212 | |||
| 1213 | if (sizeof loader_area - loader_area_used < sizeof jump) | ||
| 1214 | goto fail1; | ||
| 1215 | |||
| 1216 | memcpy (loader_area + loader_area_used, &jump, | ||
| 1217 | sizeof jump); | ||
| 1218 | loader_area_used += sizeof jump; | ||
| 1219 | |||
| 1220 | /* Close the file descriptor and return the number of bytes | ||
| 1221 | used. */ | ||
| 1222 | |||
| 1223 | close (fd); | ||
| 1224 | *size = loader_area_used; | ||
| 1225 | |||
| 1226 | /* Make sure the loader area is properly aligned. */ | ||
| 1227 | assert (!(loader_area_used & (sizeof (USER_WORD) - 1))); | ||
| 1228 | return loader_area; | ||
| 1229 | |||
| 1230 | fail1: | ||
| 1231 | errno = ENOEXEC; | ||
| 1232 | fail: | ||
| 1233 | close (fd); | ||
| 1234 | return NULL; | ||
| 1235 | } | ||